* [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom
@ 2017-10-11 23:22 James Prestwood
2017-10-11 23:22 ` [PATCHv4 2/6] atmodem: implemented sim-auth functionality in atmodem James Prestwood
` (5 more replies)
0 siblings, 6 replies; 11+ messages in thread
From: James Prestwood @ 2017-10-11 23:22 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 18793 bytes --]
The sim-auth module atom can now be used for SIM application discovery
and authentication. The atom will automatically discover SIM
applications available on the SIM and register a new DBus object under
the modem, whos name is the AID string e.g.
/modem1/A0000000871004FFFFFFFF8906190000
A list of discovered AID object paths and types can be retrieved by
calling GetApplications() under the modems (new)
org.ofono.SimAuthentication interface which returns "a{oa{sv}}" where
o = path (e.g. above)
and the dictionary contains the following properties:
Type: "Umts" or "Ims"
Name: "USim" or "ISim"
The Type signifies which interfaces the AID object will have:
Umts = org.ofono.USimApplication
Ims = org.ofono.ISimApplication
These interfaces will contain the supported USIM/ISIM authentication
algorithms. Where:
org.ofono.USimApplication has:
GetProperties()
GsmAuthenticate()
UmtsAuthenticate()
org.ofono.ISimApplication has:
GetProperties()
ImsAuthenticate()
---
src/sim-auth.c | 612 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 612 insertions(+)
diff --git a/src/sim-auth.c b/src/sim-auth.c
index 5d2f075..65a51c3 100644
--- a/src/sim-auth.c
+++ b/src/sim-auth.c
@@ -28,19 +28,104 @@
#include <glib.h>
#include <errno.h>
#include <unistd.h>
+#include <gdbus.h>
+#include <string.h>
+#include <stdio.h>
#include "ofono.h"
#include "simutil.h"
+#include "util.h"
+
+#define SIM_AUTH_MAX_RANDS 3
static GSList *g_drivers = NULL;
+/*
+ * Temporary handle used for the command authentication sequence.
+ */
+struct auth_request {
+ /* DBus values for GSM authentication */
+ DBusMessage *msg;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ /* ID from open_channel */
+ int session_id;
+ /* list of rands to calculate key (1 if umts == 1) */
+ void *rands[SIM_AUTH_MAX_RANDS];
+ int num_rands;
+ /* number of keys that have been returned */
+ int cb_count;
+ void *autn;
+ uint8_t umts : 1;
+};
+
struct ofono_sim_auth {
const struct ofono_sim_auth_driver *driver;
void *driver_data;
struct ofono_atom *atom;
+ GSList *aid_list;
+ struct ofono_sim *sim;
+ uint8_t gsm_access : 1;
+ uint8_t gsm_context : 1;
+ struct auth_request *pending;
};
+/*
+ * Find an application by path. 'path' should be a DBusMessage object path.
+ */
+static struct sim_app_record *find_aid_by_path(GSList *aid_list,
+ const char *path)
+{
+ GSList *iter = aid_list;
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+ char str[32];
+
+ encode_hex_own_buf(app->aid, 16, 0, str);
+
+ if (strstr(path, str))
+ return app;
+
+ iter = g_slist_next(iter);
+ }
+
+ return NULL;
+}
+
+/*
+ * Free all discovered AID's
+ */
+static void free_apps(struct ofono_sim_auth *sa)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(sa->atom);
+ const char *path = __ofono_atom_get_path(sa->atom);
+ GSList *iter = sa->aid_list;
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+
+ if (app->type == SIM_APP_TYPE_USIM) {
+ g_dbus_unregister_interface(conn, path,
+ OFONO_USIM_APPLICATION_INTERFACE);
+ ofono_modem_remove_interface(modem,
+ OFONO_USIM_APPLICATION_INTERFACE);
+ } else if (app->type == SIM_APP_TYPE_ISIM) {
+ g_dbus_unregister_interface(conn, path,
+ OFONO_ISIM_APPLICATION_INTERFACE);
+ ofono_modem_remove_interface(modem,
+ OFONO_USIM_APPLICATION_INTERFACE);
+ }
+
+ iter = g_slist_next(iter);
+ }
+
+ g_slist_free(sa->aid_list);
+}
+
int ofono_sim_auth_driver_register(const struct ofono_sim_auth_driver *d)
{
DBG("driver: %p, name: %s", d, d->name);
@@ -76,6 +161,10 @@ static void sim_auth_remove(struct ofono_atom *atom)
if (sa->driver && sa->driver->remove)
sa->driver->remove(sa);
+ free_apps(sa);
+
+ g_free(sa->pending);
+
g_free(sa);
}
@@ -113,9 +202,532 @@ struct ofono_sim_auth *ofono_sim_auth_create(struct ofono_modem *modem,
return sa;
}
+/*
+ * appends {oa{sv}} into an existing dict array
+ */
+static void append_dict_application(DBusMessageIter *iter, const char *path,
+ const char *type, const char *name)
+{
+ DBusMessageIter array;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &array);
+
+ ofono_dbus_dict_append(&array, "Type", DBUS_TYPE_STRING, &type);
+ ofono_dbus_dict_append(&array, "Name", DBUS_TYPE_STRING, &name);
+
+ dbus_message_iter_close_container(iter, &array);
+}
+
+/*
+ * appends a{say} onto an existing dict array
+ */
+static void append_dict_byte_array(DBusMessageIter *iter, const char *key,
+ const void *arr, uint32_t len)
+{
+ DBusMessageIter keyiter;
+ DBusMessageIter valueiter;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
+ &keyiter);
+ dbus_message_iter_append_basic(&keyiter, DBUS_TYPE_STRING, &key);
+ dbus_message_iter_open_container(&keyiter, DBUS_TYPE_ARRAY,
+ "y", &valueiter);
+ dbus_message_iter_append_fixed_array(&valueiter, DBUS_TYPE_BYTE, &arr,
+ len);
+ dbus_message_iter_close_container(&keyiter, &valueiter);
+ dbus_message_iter_close_container(iter, &keyiter);
+}
+
+static void handle_umts(struct ofono_sim_auth *sim, const uint8_t *resp,
+ uint16_t len)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ const uint8_t *res = NULL;
+ const uint8_t *ck = NULL;
+ const uint8_t *ik = NULL;
+ const uint8_t *auts = NULL;
+ const uint8_t *kc = NULL;
+
+ if (!sim_parse_umts_authenticate(resp, len, &res, &ck, &ik,
+ &auts, &kc))
+ goto umts_end;
+
+ reply = dbus_message_new_method_return(sim->pending->msg);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ "{say}", &dict);
+
+ if (auts) {
+ append_dict_byte_array(&dict, "AUTS", auts, 16);
+ } else {
+ append_dict_byte_array(&dict, "RES", res, 8);
+ append_dict_byte_array(&dict, "CK", ck, 16);
+ append_dict_byte_array(&dict, "IK", ik, 16);
+ if (kc)
+ append_dict_byte_array(&dict, "Kc", kc, 8);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+umts_end:
+ if (!reply)
+ reply = __ofono_error_not_supported(sim->pending->msg);
+
+ __ofono_dbus_pending_reply(&sim->pending->msg, reply);
+
+ sim->driver->close_channel(sim, sim->pending->session_id, NULL, NULL);
+
+ g_free(sim->pending);
+ sim->pending = NULL;
+}
+
+static void handle_gsm(struct ofono_sim_auth *sim, const uint8_t *resp,
+ uint16_t len)
+{
+ DBusMessageIter iter;
+ const uint8_t *sres = NULL;
+ const uint8_t *kc = NULL;
+
+ if (!sim_parse_gsm_authenticate(resp, len, &sres, &kc))
+ goto gsm_end;
+
+ /* initial iteration, setup the reply message */
+ if (sim->pending->cb_count == 0) {
+ sim->pending->reply = dbus_message_new_method_return(
+ sim->pending->msg);
+
+ dbus_message_iter_init_append(sim->pending->reply,
+ &sim->pending->iter);
+
+ dbus_message_iter_open_container(&sim->pending->iter,
+ DBUS_TYPE_ARRAY, "a{say}", &sim->pending->dict);
+ }
+
+ /* append the Nth sres/kc byte arrays */
+ dbus_message_iter_open_container(&sim->pending->dict, DBUS_TYPE_ARRAY,
+ "{say}", &iter);
+ append_dict_byte_array(&iter, "SRES", sres, 4);
+ append_dict_byte_array(&iter, "Kc", kc, 8);
+ dbus_message_iter_close_container(&sim->pending->dict, &iter);
+
+ sim->pending->cb_count++;
+
+ /* calculated the number of keys requested, close container */
+ if (sim->pending->cb_count == sim->pending->num_rands) {
+ dbus_message_iter_close_container(&sim->pending->iter,
+ &sim->pending->dict);
+ goto gsm_end;
+ }
+
+ return;
+
+gsm_end:
+ if (!sim->pending->reply)
+ sim->pending->reply = __ofono_error_not_supported(
+ sim->pending->msg);
+
+ __ofono_dbus_pending_reply(&sim->pending->msg, sim->pending->reply);
+
+ sim->driver->close_channel(sim, sim->pending->session_id, NULL, NULL);
+
+ g_free(sim->pending);
+
+ sim->pending = NULL;
+}
+
+static void logical_access_cb(const struct ofono_error *error,
+ const uint8_t *resp, uint16_t len, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ __ofono_dbus_pending_reply(&sim->pending->msg,
+ __ofono_error_failed(sim->pending->msg));
+ g_free(sim->pending);
+ sim->pending = NULL;
+ return;
+ }
+
+ if (sim->pending->umts)
+ handle_umts(sim, resp, len);
+ else
+ handle_gsm(sim, resp, len);
+}
+
+static void open_channel_cb(const struct ofono_error *error, int session_id,
+ void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ int i;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto error;
+
+ if (session_id == -1)
+ goto error;
+
+ /* save session ID for close_channel() */
+ sim->pending->session_id = session_id;
+
+ /*
+ * This will do the logical access num_rand times, providing a new
+ * RAND seed each time. In the UMTS case, num_rands should be 1.
+ */
+ for (i = 0; i < sim->pending->num_rands; i++) {
+ uint8_t auth_cmd[40];
+ int len = 0;
+
+ if (sim->pending->umts)
+ len = sim_build_umts_authenticate(auth_cmd, 40,
+ sim->pending->rands[i],
+ sim->pending->autn);
+ else
+ len = sim_build_gsm_authenticate(auth_cmd, 40,
+ sim->pending->rands[i]);
+
+ if (!len)
+ goto error;
+
+ sim->driver->logical_access(sim, session_id, auth_cmd, len,
+ logical_access_cb, sim);
+ }
+
+ return;
+
+error:
+ __ofono_dbus_pending_reply(&sim->pending->msg,
+ __ofono_error_failed(sim->pending->msg));
+ g_free(sim->pending);
+ sim->pending = NULL;
+}
+
+static DBusMessage *usim_gsm_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+ int i;
+ struct sim_app_record *app;
+
+ if (sim->pending)
+ return __ofono_error_busy(msg);
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return __ofono_error_not_supported(msg);
+
+ sim->pending = malloc(sizeof(struct auth_request));
+ sim->pending->msg = dbus_message_ref(msg);
+ sim->pending->umts = 0;
+ sim->pending->cb_count = 0;
+ sim->pending->num_rands = dbus_message_iter_get_element_count(&iter);
+
+ dbus_message_iter_recurse(&iter, &array);
+
+ for (i = 0; i < sim->pending->num_rands; i++) {
+ int nelement;
+ DBusMessageIter in;
+
+ dbus_message_iter_recurse(&array, &in);
+
+ dbus_message_iter_get_fixed_array(&in, &sim->pending->rands[i],
+ &nelement);
+ dbus_message_iter_next(&array);
+ }
+
+ app = find_aid_by_path(sim->aid_list, dbus_message_get_path(msg));
+
+ sim->driver->open_channel(sim, app->aid, open_channel_cb, sim);
+
+ return NULL;
+}
+
+static DBusMessage *umts_common(DBusConnection *conn, DBusMessage *msg,
+ void *data, enum sim_app_type type)
+{
+ uint8_t *rand = NULL;
+ uint8_t *autn = NULL;
+ uint32_t rlen;
+ uint32_t alen;
+ struct ofono_sim_auth *sim = data;
+ struct sim_app_record *app;
+
+ if (sim->pending)
+ return __ofono_error_busy(msg);
+
+ /* get RAND/AUTN and setup handle args */
+ dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE, &rand, &rlen, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE, &autn, &alen,
+ DBUS_TYPE_INVALID);
+
+ if (rlen != 16 || alen != 16) {
+ g_free(sim->pending);
+ sim->pending = NULL;
+ return __ofono_error_invalid_args(msg);
+ }
+
+ sim->pending = g_new0(struct auth_request, 1);
+ sim->pending->msg = dbus_message_ref(msg);
+ sim->pending->rands[0] = rand;
+ sim->pending->num_rands = 1;
+ sim->pending->autn = autn;
+ sim->pending->umts = 1;
+
+ app = find_aid_by_path(sim->aid_list, dbus_message_get_path(msg));
+
+ sim->driver->open_channel(sim, app->aid, open_channel_cb, sim);
+
+ return NULL;
+}
+
+static DBusMessage *get_applications(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_sim_auth *sim = data;
+ const char *path = __ofono_atom_get_path(sim->atom);
+ int ret;
+ char object[strlen(path) + 33];
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+ DBusMessageIter dict;
+ GSList *aid_iter;
+
+ if (!sim->aid_list)
+ return __ofono_error_busy(msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{oa{sv}}",
+ &array);
+
+ aid_iter = sim->aid_list;
+
+ while (aid_iter) {
+ struct sim_app_record *app = aid_iter->data;
+
+ ret = sprintf(object, "%s/", path);
+ encode_hex_own_buf(app->aid, 16, 0, object + ret);
+
+ switch (app->type) {
+ case SIM_APP_TYPE_ISIM:
+ dbus_message_iter_open_container(&array,
+ DBUS_TYPE_DICT_ENTRY, NULL, &dict);
+ append_dict_application(&dict, object, "Ims", "ISim");
+ dbus_message_iter_close_container(&array, &dict);
+
+ break;
+ case SIM_APP_TYPE_USIM:
+ dbus_message_iter_open_container(&array,
+ DBUS_TYPE_DICT_ENTRY, NULL, &dict);
+ append_dict_application(&dict, object, "Umts", "USim");
+ dbus_message_iter_close_container(&array, &dict);
+
+ break;
+ default:
+ break;
+ }
+
+ aid_iter = g_slist_next(aid_iter);
+ }
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static DBusMessage *send_properties(DBusConnection *conn, DBusMessage *msg,
+ void *data, const char *type, const char *name)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}",
+ &array);
+
+ ofono_dbus_dict_append(&array, "Type", DBUS_TYPE_STRING, &type);
+ ofono_dbus_dict_append(&array, "Name", DBUS_TYPE_STRING, &name);
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static DBusMessage *usim_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return send_properties(conn, msg, data, "Umts", "USim");
+}
+
+static DBusMessage *isim_get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return send_properties(conn, msg, data, "Ims", "ISim");
+}
+
+static DBusMessage *isim_ims_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return umts_common(conn, msg, data, SIM_APP_TYPE_ISIM);
+}
+
+static DBusMessage *usim_umts_authenticate(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ return umts_common(conn, msg, data, SIM_APP_TYPE_USIM);
+}
+
+static const GDBusMethodTable sim_authentication[] = {
+ { GDBUS_METHOD("GetApplications",
+ NULL,
+ GDBUS_ARGS({"applications", "a{oa{sv}}"}),
+ get_applications) },
+ { }
+};
+
+static const GDBusMethodTable sim_auth_usim_app[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL,
+ GDBUS_ARGS({"properties", "a{sv}"}),
+ usim_get_properties) },
+ { GDBUS_ASYNC_METHOD("GsmAuthenticate",
+ GDBUS_ARGS({"rands", "aay"}),
+ GDBUS_ARGS({"keys", "a{say}"}),
+ usim_gsm_authenticate) },
+ { GDBUS_ASYNC_METHOD("UmtsAuthenticate",
+ GDBUS_ARGS({"rand", "ay"}, {"autn", "ay"}),
+ GDBUS_ARGS({"return", "a{sv}"}),
+ usim_umts_authenticate) },
+ { }
+};
+
+static const GDBusMethodTable sim_auth_isim_app[] = {
+ { GDBUS_ASYNC_METHOD("GetProperties",
+ NULL,
+ GDBUS_ARGS({"properties", "a{sv}"}),
+ isim_get_properties) },
+ { GDBUS_ASYNC_METHOD("ImsAuthenticate",
+ GDBUS_ARGS({"rand", "ay"}, {"autn", "ay"}),
+ GDBUS_ARGS({"return", "a{sv}"}),
+ isim_ims_authenticate) },
+ { }
+};
+
+static void discover_apps_cb(const struct ofono_error *error,
+ const unsigned char *dataobj,
+ int len, void *data)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_sim_auth *sim = data;
+ struct ofono_modem *modem = __ofono_atom_get_modem(sim->atom);
+ const char *path = __ofono_atom_get_path(sim->atom);
+ GSList *iter;
+ char app_path[strlen(path) + 34];
+ int ret;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto parse_error;
+
+ sim->aid_list = sim_parse_app_template_entries(dataobj, len);
+
+ if (!sim->aid_list)
+ goto parse_error;
+
+ iter = sim->aid_list;
+
+ ret = sprintf(app_path, "%s/", path);
+
+ while (iter) {
+ struct sim_app_record *app = iter->data;
+
+ switch (app->type) {
+ case SIM_APP_TYPE_USIM:
+ encode_hex_own_buf(app->aid, 16, 0, app_path + ret);
+
+ app_path[ret + 32] = '\0';
+
+ g_dbus_register_interface(conn, app_path,
+ OFONO_USIM_APPLICATION_INTERFACE,
+ sim_auth_usim_app, NULL, NULL,
+ sim, NULL);
+ break;
+ case SIM_APP_TYPE_ISIM:
+ encode_hex_own_buf(app->aid, 16, 0, app_path + ret);
+
+ app_path[ret + 32] = '\0';
+
+ g_dbus_register_interface(conn, app_path,
+ OFONO_ISIM_APPLICATION_INTERFACE,
+ sim_auth_isim_app, NULL, NULL,
+ sim, NULL);
+ break;
+ default:
+ DBG("Unknown SIM application '%04x'", app->type);
+ /*
+ * If we get here, the SIM application was not ISIM
+ * or USIM, skip.
+ */
+ }
+
+ iter = g_slist_next(iter);
+ }
+
+ /*
+ * Now SimAuthentication interface can be registered since app
+ * discovery has completed
+ */
+ g_dbus_register_interface(conn, path,
+ OFONO_SIM_AUTHENTICATION_INTERFACE,
+ sim_authentication, NULL, NULL,
+ sim, NULL);
+ ofono_modem_add_interface(modem,
+ OFONO_SIM_AUTHENTICATION_INTERFACE);
+
+ return;
+
+parse_error:
+ /*
+ * Something went wrong parsing the AID list, it can't be assumed that
+ * any previously parsed AID's are valid so free them all.
+ */
+ DBG("Error parsing app list");
+}
+
void ofono_sim_auth_register(struct ofono_sim_auth *sa)
{
+ struct ofono_modem *modem = __ofono_atom_get_modem(sa->atom);
+
__ofono_atom_register(sa->atom, sim_auth_unregister);
+
+ /* Do SIM application discovery, the cb will register DBus ifaces */
+ sa->driver->list_apps(sa, discover_apps_cb, sa);
+
+ sa->sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem);
+
+ sa->gsm_access = __ofono_sim_ust_service_available(sa->sim,
+ SIM_UST_SERVICE_GSM_ACCESS);
+ sa->gsm_context = __ofono_sim_ust_service_available(sa->sim,
+ SIM_UST_SERVICE_GSM_SECURITY_CONTEXT);
}
void ofono_sim_auth_remove(struct ofono_sim_auth *sa)
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCHv4 2/6] atmodem: implemented sim-auth functionality in atmodem 2017-10-11 23:22 [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom James Prestwood @ 2017-10-11 23:22 ` James Prestwood 2017-10-11 23:22 ` [PATCHv4 3/6] xmm7xxx: add sim-auth driver to xmm7xxx plugin James Prestwood ` (4 subsequent siblings) 5 siblings, 0 replies; 11+ messages in thread From: James Prestwood @ 2017-10-11 23:22 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 5085 bytes --] Implemented the core API's needed for sim-auth: list_apps: already implemented open_channel: Opens a logical channel with +CCHO close_channel: Closes logical channel with +CCHC logical_access: Access an opened channel with +CGLA --- drivers/atmodem/sim-auth.c | 152 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/drivers/atmodem/sim-auth.c b/drivers/atmodem/sim-auth.c index 271ceed..d04f561 100644 --- a/drivers/atmodem/sim-auth.c +++ b/drivers/atmodem/sim-auth.c @@ -25,6 +25,7 @@ #define _GNU_SOURCE #include <string.h> +#include <stdio.h> #include <glib.h> @@ -35,6 +36,7 @@ #include "gatresult.h" #include "simutil.h" #include "vendor.h" +#include "util.h" #include "atmodem.h" @@ -44,6 +46,8 @@ struct sim_auth_data { }; static const char *cuad_prefix[] = { "+CUAD:", NULL }; +static const char *ccho_prefix[] = { "+CCHO:", NULL }; +static const char *cgla_prefix[] = { "+CGLA:", NULL }; static void at_discover_apps_cb(gboolean ok, GAtResult *result, gpointer user_data) @@ -110,6 +114,151 @@ static void at_discover_apps(struct ofono_sim_auth *sa, CALLBACK_WITH_FAILURE(cb, NULL, 0, data); } +static void at_open_channel_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + GAtResultIter iter; + ofono_sim_open_channel_cb_t cb = cbd->cb; + struct ofono_error error; + int session_id = -1; + + decode_at_error(&error, g_at_result_final_response(result)); + + if (!ok) + goto error; + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+CCHO:")) + goto error; + + if (!g_at_result_iter_next_number(&iter, &session_id)) + goto error; + + cb(&error, session_id, cbd->data); + + return; + +error: + cb(&error, -1, cbd->data); +} + +static void at_open_channel(struct ofono_sim_auth *sa, const uint8_t *aid, + ofono_sim_open_channel_cb_t cb, void *data) +{ + struct sim_auth_data *sad = ofono_sim_auth_get_data(sa); + struct cb_data *cbd = cb_data_new(cb, data); + char cmd[43]; + int ret = 0; + + strcpy(cmd, "AT+CCHO=\""); + ret += 9; + + encode_hex_own_buf(aid, 16, 0, cmd + ret); + ret += 32; + + strcpy(cmd + ret, "\""); + + if (g_at_chat_send(sad->chat, cmd, ccho_prefix, at_open_channel_cb, + cbd, g_free) > 0) + return; + + g_free(cbd); + + CALLBACK_WITH_FAILURE(cb, -1, data); +} + +static void at_close_channel_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_sim_close_channel_cb_t cb = cbd->cb; + struct ofono_error error; + + decode_at_error(&error, g_at_result_final_response(result)); + + if (cb) + cb(&error, cbd->data); +} + +static void at_close_channel(struct ofono_sim_auth *sa, int session_id, + ofono_sim_close_channel_cb_t cb, void *data) +{ + struct sim_auth_data *sad = ofono_sim_auth_get_data(sa); + struct cb_data *cbd = cb_data_new(cb, data); + char cmd[15]; + + sprintf(cmd, "AT+CCHC=%d", session_id); + + g_at_chat_send(sad->chat, cmd, NULL, at_close_channel_cb, cbd, g_free); +} + +static void logical_access_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_logical_access_cb_t cb = cbd->cb; + struct ofono_error error; + const char *str_data; + uint8_t *raw; + gint len = 0; + GAtResultIter iter; + + decode_at_error(&error, g_at_result_final_response(result)); + + if (!ok) + goto error; + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+CGLA:")) + goto error; + + if (!g_at_result_iter_next_number(&iter, &len)) + goto error; + + if (!g_at_result_iter_next_string(&iter, &str_data)) + goto error; + + raw = alloca(len / 2); + + decode_hex_own_buf(str_data, len, NULL, 0, raw); + + cb(&error, raw, len / 2, cbd->data); + + return; + +error: + cb(&error, NULL, 0, cbd->data); +} + +static void at_logical_access(struct ofono_sim_auth *sa, int session_id, + const uint8_t *pdu, uint16_t len, ofono_logical_access_cb_t cb, + void *data) + +{ + struct sim_auth_data *sad = ofono_sim_auth_get_data(sa); + struct cb_data *cbd = cb_data_new(cb, data); + int ret = 0; + char cmd[(len * 2) + 19]; + + ret = sprintf(cmd, "AT+CGLA=%d,%d,\"", session_id, len * 2); + + encode_hex_own_buf(pdu, len, 0, cmd + ret); + ret += len * 2; + + strcpy(cmd + ret, "\""); + + if (g_at_chat_send(sad->chat, cmd, cgla_prefix, logical_access_cb, + cbd, g_free) > 0) + return; + + g_free(cbd); + + CALLBACK_WITH_FAILURE(cb, NULL, 0, data); +} + static gboolean at_sim_auth_register(gpointer user) { struct ofono_sim_auth *sa = user; @@ -151,6 +300,9 @@ static struct ofono_sim_auth_driver driver = { .probe = at_sim_auth_probe, .remove = at_sim_auth_remove, .list_apps = at_discover_apps, + .open_channel = at_open_channel, + .close_channel = at_close_channel, + .logical_access = at_logical_access }; void at_sim_auth_init(void) -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv4 3/6] xmm7xxx: add sim-auth driver to xmm7xxx plugin 2017-10-11 23:22 [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom James Prestwood 2017-10-11 23:22 ` [PATCHv4 2/6] atmodem: implemented sim-auth functionality in atmodem James Prestwood @ 2017-10-11 23:22 ` James Prestwood 2017-10-12 14:53 ` Denis Kenzior 2017-10-11 23:22 ` [PATCHv4 4/6] phonesim: Added sim-auth to phonesim plugin James Prestwood ` (3 subsequent siblings) 5 siblings, 1 reply; 11+ messages in thread From: James Prestwood @ 2017-10-11 23:22 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1055 bytes --] --- plugins/xmm7xxx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/xmm7xxx.c b/plugins/xmm7xxx.c index 5cb843b..ff0cb4c 100644 --- a/plugins/xmm7xxx.c +++ b/plugins/xmm7xxx.c @@ -49,6 +49,7 @@ #include <ofono/stk.h> #include <ofono/lte.h> #include <ofono/ims.h> +#include <ofono/sim-auth.h> #include <drivers/atmodem/atutil.h> #include <drivers/atmodem/vendor.h> @@ -61,6 +62,7 @@ struct xmm7xxx_data { struct ofono_sim *sim; ofono_bool_t have_sim; ofono_bool_t sms_phonebook_added; + struct ofono_sim_auth *sim_auth; }; static void xmm7xxx_debug(const char *str, void *user_data) @@ -286,6 +288,7 @@ static void xmm7xxx_pre_sim(struct ofono_modem *modem) ofono_devinfo_create(modem, OFONO_VENDOR_IFX, "atmodem", data->chat); data->sim = ofono_sim_create(modem, OFONO_VENDOR_IFX, "atmodem", data->chat); + data->sim_auth = ofono_sim_auth_create(modem, 0, "atmodem", data->chat); } static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data) -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHv4 3/6] xmm7xxx: add sim-auth driver to xmm7xxx plugin 2017-10-11 23:22 ` [PATCHv4 3/6] xmm7xxx: add sim-auth driver to xmm7xxx plugin James Prestwood @ 2017-10-12 14:53 ` Denis Kenzior 0 siblings, 0 replies; 11+ messages in thread From: Denis Kenzior @ 2017-10-12 14:53 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1434 bytes --] Hi James, On 10/11/2017 06:22 PM, James Prestwood wrote: > --- > plugins/xmm7xxx.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/plugins/xmm7xxx.c b/plugins/xmm7xxx.c > index 5cb843b..ff0cb4c 100644 > --- a/plugins/xmm7xxx.c > +++ b/plugins/xmm7xxx.c > @@ -49,6 +49,7 @@ > #include <ofono/stk.h> > #include <ofono/lte.h> > #include <ofono/ims.h> > +#include <ofono/sim-auth.h> > > #include <drivers/atmodem/atutil.h> > #include <drivers/atmodem/vendor.h> > @@ -61,6 +62,7 @@ struct xmm7xxx_data { > struct ofono_sim *sim; > ofono_bool_t have_sim; > ofono_bool_t sms_phonebook_added; > + struct ofono_sim_auth *sim_auth; No need to make this a member variable. Just treat it like the other atoms. 'sim' atom is nearly always special. > }; > > static void xmm7xxx_debug(const char *str, void *user_data) > @@ -286,6 +288,7 @@ static void xmm7xxx_pre_sim(struct ofono_modem *modem) > ofono_devinfo_create(modem, OFONO_VENDOR_IFX, "atmodem", data->chat); > data->sim = ofono_sim_create(modem, OFONO_VENDOR_IFX, "atmodem", > data->chat); > + data->sim_auth = ofono_sim_auth_create(modem, 0, "atmodem", data->chat); This belongs in post_sim. If the SIM is PIN locked, then the application discovery will fail. > } > > static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data) > Regards, -Denis ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv4 4/6] phonesim: Added sim-auth to phonesim plugin 2017-10-11 23:22 [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom James Prestwood 2017-10-11 23:22 ` [PATCHv4 2/6] atmodem: implemented sim-auth functionality in atmodem James Prestwood 2017-10-11 23:22 ` [PATCHv4 3/6] xmm7xxx: add sim-auth driver to xmm7xxx plugin James Prestwood @ 2017-10-11 23:22 ` James Prestwood 2017-10-12 14:54 ` Denis Kenzior 2017-10-11 23:22 ` [PATCHv4 5/6] test: added tests for GSM/UMTS auth algorithms James Prestwood ` (2 subsequent siblings) 5 siblings, 1 reply; 11+ messages in thread From: James Prestwood @ 2017-10-11 23:22 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 977 bytes --] --- plugins/phonesim.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/phonesim.c b/plugins/phonesim.c index 16bccd5..345c41e 100644 --- a/plugins/phonesim.c +++ b/plugins/phonesim.c @@ -61,6 +61,7 @@ #include <ofono/gnss.h> #include <ofono/handsfree.h> #include <ofono/siri.h> +#include <ofono/sim-auth.h> #include <drivers/atmodem/vendor.h> #include <drivers/atmodem/atutil.h> @@ -84,6 +85,7 @@ struct phonesim_data { unsigned int hfp_watch; int batt_level; struct ofono_sim *sim; + struct ofono_sim_auth *sim_auth; }; struct gprs_context_data { @@ -839,6 +841,8 @@ static void phonesim_pre_sim(struct ofono_modem *modem) ofono_voicecall_create(modem, 0, "calypsomodem", data->chat); else ofono_voicecall_create(modem, 0, "atmodem", data->chat); + + data->sim_auth = ofono_sim_auth_create(modem, 0, "atmodem", data->chat); } static void phonesim_post_sim(struct ofono_modem *modem) -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHv4 4/6] phonesim: Added sim-auth to phonesim plugin 2017-10-11 23:22 ` [PATCHv4 4/6] phonesim: Added sim-auth to phonesim plugin James Prestwood @ 2017-10-12 14:54 ` Denis Kenzior 0 siblings, 0 replies; 11+ messages in thread From: Denis Kenzior @ 2017-10-12 14:54 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1182 bytes --] On 10/11/2017 06:22 PM, James Prestwood wrote: > --- > plugins/phonesim.c | 4 ++++ > 1 file changed, 4 insertions(+) > > diff --git a/plugins/phonesim.c b/plugins/phonesim.c > index 16bccd5..345c41e 100644 > --- a/plugins/phonesim.c > +++ b/plugins/phonesim.c > @@ -61,6 +61,7 @@ > #include <ofono/gnss.h> > #include <ofono/handsfree.h> > #include <ofono/siri.h> > +#include <ofono/sim-auth.h> > > #include <drivers/atmodem/vendor.h> > #include <drivers/atmodem/atutil.h> > @@ -84,6 +85,7 @@ struct phonesim_data { > unsigned int hfp_watch; > int batt_level; > struct ofono_sim *sim; > + struct ofono_sim_auth *sim_auth; No need to track this... > }; > > struct gprs_context_data { > @@ -839,6 +841,8 @@ static void phonesim_pre_sim(struct ofono_modem *modem) > ofono_voicecall_create(modem, 0, "calypsomodem", data->chat); > else > ofono_voicecall_create(modem, 0, "atmodem", data->chat); > + > + data->sim_auth = ofono_sim_auth_create(modem, 0, "atmodem", data->chat); Put this inside post_sim. > } > > static void phonesim_post_sim(struct ofono_modem *modem) > Regards, -Denis ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv4 5/6] test: added tests for GSM/UMTS auth algorithms 2017-10-11 23:22 [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom James Prestwood ` (2 preceding siblings ...) 2017-10-11 23:22 ` [PATCHv4 4/6] phonesim: Added sim-auth to phonesim plugin James Prestwood @ 2017-10-11 23:22 ` James Prestwood 2017-10-12 14:52 ` Denis Kenzior 2017-10-11 23:22 ` [PATCHv4 6/6] doc: documentation for SimAuth dbus interfaces James Prestwood 2017-10-12 14:48 ` [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom Denis Kenzior 5 siblings, 1 reply; 11+ messages in thread From: James Prestwood @ 2017-10-11 23:22 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 2551 bytes --] --- test/run-isim-umts-auth | 38 ++++++++++++++++++++++++++++++++++++++ test/run-usim-gsm-auth | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100755 test/run-isim-umts-auth create mode 100755 test/run-usim-gsm-auth diff --git a/test/run-isim-umts-auth b/test/run-isim-umts-auth new file mode 100755 index 0000000..a521425 --- /dev/null +++ b/test/run-isim-umts-auth @@ -0,0 +1,38 @@ +#!/usr/bin/python3 + +import dbus +import sys + +bus = dbus.SystemBus() + +if len(sys.argv) == 4: + path = sys.argv[1] + rand = sys.argv[2] + autn = sys.argv[3] + + sim_auth = dbus.Interface(bus.get_object('org.ofono', path), + 'org.ofono.SimAuthentication') + apps = sim_auth.GetApplications() + for i in apps: + if apps[i]['Type'] == 'Ims': + ims_path = i + + if not ims_path: + print("No Ims application found") + quit() + + isim_auth = dbus.Interface(bus.get_object('org.ofono', ims_path), + 'org.ofono.ISimApplication') + ret = isim_auth.ImsAuthenticate(bytearray.fromhex(rand), + bytearray.fromhex(autn)) + + if 'auts' in ret: + print('Sync Failure') + print('AUTS: ' + ''.join('%02x' % x for x in ret['AUTS'])) + else: + print('Success') + print('RES: ' + ''.join('%02x' % x for x in ret['RES'])) + print('CK: ' + ''.join('%02x' % x for x in ret['CK'])) + print('IK: ' + ''.join('%02x' % x for x in ret['IK'])) +else: + print("./run-isim-umts-auth <modem> <rand> <autn>") diff --git a/test/run-usim-gsm-auth b/test/run-usim-gsm-auth new file mode 100755 index 0000000..b97a557 --- /dev/null +++ b/test/run-usim-gsm-auth @@ -0,0 +1,36 @@ +#!/usr/bin/python3 + +import dbus +import sys + +bus = dbus.SystemBus() + +if len(sys.argv) < 6 and len(sys.argv) > 2: + path = sys.argv[1] + + rands = [] + for i in sys.argv[2:]: + rands.append(bytearray.fromhex(i)) + + sim_auth = dbus.Interface(bus.get_object('org.ofono', path), + 'org.ofono.SimAuthentication') + apps = sim_auth.GetApplications() + + for i in apps: + if apps[i]['Type'] == 'Umts': + umts_path = i + + if not umts_path: + print("No Umts application found") + quit() + + umts = dbus.Interface(bus.get_object('org.ofono', umts_path), + 'org.ofono.USimApplication') + av = umts.GsmAuthenticate(rands) + + for i in av: + print('SRES: ' + ''.join('%02x' % x for x in i['SRES'])) + print('KC: ' + ''.join('%02x' % x for x in i['Kc'])) + +else: + print("./run-usim-gsm-auth <modem> <rands>...[up to 3]") -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHv4 5/6] test: added tests for GSM/UMTS auth algorithms 2017-10-11 23:22 ` [PATCHv4 5/6] test: added tests for GSM/UMTS auth algorithms James Prestwood @ 2017-10-12 14:52 ` Denis Kenzior 0 siblings, 0 replies; 11+ messages in thread From: Denis Kenzior @ 2017-10-12 14:52 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 392 bytes --] Hi James, On 10/11/2017 06:22 PM, James Prestwood wrote: > --- > test/run-isim-umts-auth | 38 ++++++++++++++++++++++++++++++++++++++ > test/run-usim-gsm-auth | 36 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 74 insertions(+) > create mode 100755 test/run-isim-umts-auth > create mode 100755 test/run-usim-gsm-auth > Applied, thanks. Regards, -Denis ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCHv4 6/6] doc: documentation for SimAuth dbus interfaces 2017-10-11 23:22 [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom James Prestwood ` (3 preceding siblings ...) 2017-10-11 23:22 ` [PATCHv4 5/6] test: added tests for GSM/UMTS auth algorithms James Prestwood @ 2017-10-11 23:22 ` James Prestwood 2017-10-12 14:51 ` Denis Kenzior 2017-10-12 14:48 ` [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom Denis Kenzior 5 siblings, 1 reply; 11+ messages in thread From: James Prestwood @ 2017-10-11 23:22 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 3651 bytes --] --- doc/sim-auth-api.txt | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 doc/sim-auth-api.txt diff --git a/doc/sim-auth-api.txt b/doc/sim-auth-api.txt new file mode 100644 index 0000000..e040776 --- /dev/null +++ b/doc/sim-auth-api.txt @@ -0,0 +1,104 @@ +SimAuthentication heiarchy [experimental] +=========================================== + +Service org.ofono +Interface org.ofono.SimAuthentication +Object path [variable prefix]/{modem0,modem1,...} + +Methods array{object,dict} GetApplications() + + Get an array of all SIM applications found during + discovery. In the format "a{oa{sv}}" where 'o' is + the object path for the application e.g. + + o = "/modem1/A0000000871004FFFFFFFF8906190000" + + Each dictionary will contain 'Type' e.g. 'Ims' and + 'Name' e.g. 'ISim' + + For each application there will be a corresponding + object that matches the path (o). The type will + signify which interfaces are under that object (below). + + type = Umts --> org.ofono.USimApplication + type = Ims --> org.ofono.ISimApplication + +SimAuth USIM application heiarchy [experimental] +=========================================== + +Service org.ofono +Interface org.ofono.USimApplication +Object path [variable prefix]/{modem0,modem1,...}/{AID name} + +Methods dict GetProperties() + + Returns properties for the USimApplication. See + properties section for available properties. + + array{dict{string, array{byte}}} + GsmAuthenticate(array{array{byte}} rands) + + Run the USIM application GSM AUTHENTICATE algorithm + with N random challenges 'rands'. This should be an + array of an array of bytes ("aay"). The number of + random challenges is limited to a maximum of 3. + + Returns the derived Kc/SRES values as an array of + dictionaries. The index of each dictionary matches + the index of the rand value in the method call. The + keys for each dictionary are "Kc" and "SRES" and both + are arrays of bytes. + + Possible Errors: + [service].Error.NotSupported + [service].Error.Busy + + dict{string, array{byte}} + UmtsAuthenticate(array{byte} rand, array{byte} autn) + + Run the UMTS AUTHENTICATE algorithm in the 3G + context with 'rand' and 'autn'. A dictionary will be + returned containing 'RES', 'CK', 'IK' and possibly + 'Kc' if service 27 is available. If there was a + sync error 'AUTS' will be returned. + + Possible Errors: [service].Error.NotSupported + +Properties string Type [readonly] + + Type of application: 'Umts' + + string Name [readonly] + + Human readable name: 'USim' + +SimAuth ISIM application heiarchy [experimental] +=========================================== + +Service org.ofono +Interface org.ofono.ISimApplication +Object [variable prefix]/{modem0,modem1,...}/{AID name} + +Methods dict GetProperties() + + Returns properties for the ISimApplication. See + the properties section for available properties. + + dict{string, array{byte} + ImsAuthenticate(array{byte} rand, array{byte} autn) + + Run the UMTS AUTHENTICATE algorithm in the IMS + context with 'rand' and 'autn'. A dictionary will be + returned containing 'RES', 'CK', 'IK' and possibly + 'Kc' if service 27 is available. If there was a + sync error 'AUTS' will be returned. + + Possible Errors: [service].Error.NotSupported + +Properties string Type [readonly] + + Type of application: 'Ims' + + string Name [readonly] + + Human readable name: 'ISim' -- 2.7.4 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHv4 6/6] doc: documentation for SimAuth dbus interfaces 2017-10-11 23:22 ` [PATCHv4 6/6] doc: documentation for SimAuth dbus interfaces James Prestwood @ 2017-10-12 14:51 ` Denis Kenzior 0 siblings, 0 replies; 11+ messages in thread From: Denis Kenzior @ 2017-10-12 14:51 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 282 bytes --] Hi James, On 10/11/2017 06:22 PM, James Prestwood wrote: > --- > doc/sim-auth-api.txt | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 104 insertions(+) > create mode 100644 doc/sim-auth-api.txt > Applied, thanks. Regards, -Denis ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom 2017-10-11 23:22 [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom James Prestwood ` (4 preceding siblings ...) 2017-10-11 23:22 ` [PATCHv4 6/6] doc: documentation for SimAuth dbus interfaces James Prestwood @ 2017-10-12 14:48 ` Denis Kenzior 5 siblings, 0 replies; 11+ messages in thread From: Denis Kenzior @ 2017-10-12 14:48 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 21908 bytes --] Hi James, On 10/11/2017 06:22 PM, James Prestwood wrote: > The sim-auth module atom can now be used for SIM application discovery > and authentication. The atom will automatically discover SIM > applications available on the SIM and register a new DBus object under > the modem, whos name is the AID string e.g. > > /modem1/A0000000871004FFFFFFFF8906190000 > > A list of discovered AID object paths and types can be retrieved by > calling GetApplications() under the modems (new) > org.ofono.SimAuthentication interface which returns "a{oa{sv}}" where > > o = path (e.g. above) > > and the dictionary contains the following properties: > > Type: "Umts" or "Ims" > Name: "USim" or "ISim" > > The Type signifies which interfaces the AID object will have: > > Umts = org.ofono.USimApplication > Ims = org.ofono.ISimApplication > > These interfaces will contain the supported USIM/ISIM authentication > algorithms. Where: > > org.ofono.USimApplication has: > GetProperties() > GsmAuthenticate() > UmtsAuthenticate() > > org.ofono.ISimApplication has: > GetProperties() > ImsAuthenticate() > --- > src/sim-auth.c | 612 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 612 insertions(+) > > diff --git a/src/sim-auth.c b/src/sim-auth.c > index 5d2f075..65a51c3 100644 > --- a/src/sim-auth.c > +++ b/src/sim-auth.c > @@ -28,19 +28,104 @@ > #include <glib.h> > #include <errno.h> > #include <unistd.h> > +#include <gdbus.h> > +#include <string.h> > +#include <stdio.h> > > #include "ofono.h" > > #include "simutil.h" > +#include "util.h" > + > +#define SIM_AUTH_MAX_RANDS 3 > > static GSList *g_drivers = NULL; > > +/* > + * Temporary handle used for the command authentication sequence. > + */ > +struct auth_request { > + /* DBus values for GSM authentication */ > + DBusMessage *msg; > + DBusMessage *reply; > + DBusMessageIter iter; > + DBusMessageIter dict; > + /* ID from open_channel */ > + int session_id; > + /* list of rands to calculate key (1 if umts == 1) */ > + void *rands[SIM_AUTH_MAX_RANDS]; > + int num_rands; > + /* number of keys that have been returned */ > + int cb_count; > + void *autn; > + uint8_t umts : 1; > +}; > + > struct ofono_sim_auth { > const struct ofono_sim_auth_driver *driver; > void *driver_data; > struct ofono_atom *atom; > + GSList *aid_list; > + struct ofono_sim *sim; You only use sim inside ofono_sim_auth_register. No point in making it a class variable then. > + uint8_t gsm_access : 1; > + uint8_t gsm_context : 1; > + struct auth_request *pending; > }; > > +/* > + * Find an application by path. 'path' should be a DBusMessage object path. > + */ > +static struct sim_app_record *find_aid_by_path(GSList *aid_list, > + const char *path) > +{ > + GSList *iter = aid_list; > + Why don't you just use strrchr to find the last '/' and use the string starting at that position + 1 (e.g. the actual hex-encoded AID) for comparisons in the while loop? > + while (iter) { > + struct sim_app_record *app = iter->data; > + char str[32]; > + > + encode_hex_own_buf(app->aid, 16, 0, str); > + > + if (strstr(path, str)) given above, this could be a simple strcmp > + return app; > + > + iter = g_slist_next(iter); > + } > + > + return NULL; > +} > + > +/* > + * Free all discovered AID's > + */ > +static void free_apps(struct ofono_sim_auth *sa) > +{ > + DBusConnection *conn = ofono_dbus_get_connection(); > + struct ofono_modem *modem = __ofono_atom_get_modem(sa->atom); > + const char *path = __ofono_atom_get_path(sa->atom); > + GSList *iter = sa->aid_list; > + > + while (iter) { > + struct sim_app_record *app = iter->data; > + > + if (app->type == SIM_APP_TYPE_USIM) { > + g_dbus_unregister_interface(conn, path, > + OFONO_USIM_APPLICATION_INTERFACE); > + ofono_modem_remove_interface(modem, > + OFONO_USIM_APPLICATION_INTERFACE); This interface is not on the modem object, so this isn't needed. You also don't have a corresponding ofono_modem_add_interface in the first place. > + } else if (app->type == SIM_APP_TYPE_ISIM) { > + g_dbus_unregister_interface(conn, path, > + OFONO_ISIM_APPLICATION_INTERFACE); > + ofono_modem_remove_interface(modem, > + OFONO_USIM_APPLICATION_INTERFACE); Same here > + } > + > + iter = g_slist_next(iter); > + } > + > + g_slist_free(sa->aid_list); > +} > + > int ofono_sim_auth_driver_register(const struct ofono_sim_auth_driver *d) > { > DBG("driver: %p, name: %s", d, d->name); > @@ -76,6 +161,10 @@ static void sim_auth_remove(struct ofono_atom *atom) > if (sa->driver && sa->driver->remove) > sa->driver->remove(sa); > > + free_apps(sa); > + > + g_free(sa->pending); > + Actually this belongs in sim_auth_unregister. We have two basic states for the atom: 1. 'created'. E.g. ofono_atom_create has been called 2. 'registered' E.g. ofono_atom_register has been called. Any data structure created after state '2' is entered should be torn down in the callback given to __ofono_atom_register. e.g. sim_auth_unregister in this case. > g_free(sa); > } > > @@ -113,9 +202,532 @@ struct ofono_sim_auth *ofono_sim_auth_create(struct ofono_modem *modem, > return sa; > } > > +/* > + * appends {oa{sv}} into an existing dict array > + */ > +static void append_dict_application(DBusMessageIter *iter, const char *path, > + const char *type, const char *name) > +{ > + DBusMessageIter array; > + > + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); > + > + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &array); > + > + ofono_dbus_dict_append(&array, "Type", DBUS_TYPE_STRING, &type); > + ofono_dbus_dict_append(&array, "Name", DBUS_TYPE_STRING, &name); > + > + dbus_message_iter_close_container(iter, &array); > +} > + > +/* > + * appends a{say} onto an existing dict array > + */ > +static void append_dict_byte_array(DBusMessageIter *iter, const char *key, > + const void *arr, uint32_t len) > +{ > + DBusMessageIter keyiter; > + DBusMessageIter valueiter; > + > + dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL, > + &keyiter); > + dbus_message_iter_append_basic(&keyiter, DBUS_TYPE_STRING, &key); > + dbus_message_iter_open_container(&keyiter, DBUS_TYPE_ARRAY, > + "y", &valueiter); > + dbus_message_iter_append_fixed_array(&valueiter, DBUS_TYPE_BYTE, &arr, > + len); > + dbus_message_iter_close_container(&keyiter, &valueiter); > + dbus_message_iter_close_container(iter, &keyiter); > +} > + > +static void handle_umts(struct ofono_sim_auth *sim, const uint8_t *resp, > + uint16_t len) > +{ > + DBusMessage *reply = NULL; > + DBusMessageIter iter; > + DBusMessageIter dict; > + const uint8_t *res = NULL; > + const uint8_t *ck = NULL; > + const uint8_t *ik = NULL; > + const uint8_t *auts = NULL; > + const uint8_t *kc = NULL; > + > + if (!sim_parse_umts_authenticate(resp, len, &res, &ck, &ik, > + &auts, &kc)) > + goto umts_end; > + > + reply = dbus_message_new_method_return(sim->pending->msg); > + > + dbus_message_iter_init_append(reply, &iter); > + > + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, > + "{say}", &dict); > + > + if (auts) { > + append_dict_byte_array(&dict, "AUTS", auts, 16); > + } else { > + append_dict_byte_array(&dict, "RES", res, 8); > + append_dict_byte_array(&dict, "CK", ck, 16); > + append_dict_byte_array(&dict, "IK", ik, 16); > + if (kc) > + append_dict_byte_array(&dict, "Kc", kc, 8); > + } > + > + dbus_message_iter_close_container(&iter, &dict); > + > +umts_end: > + if (!reply) > + reply = __ofono_error_not_supported(sim->pending->msg); > + > + __ofono_dbus_pending_reply(&sim->pending->msg, reply); > + > + sim->driver->close_channel(sim, sim->pending->session_id, NULL, NULL); > + > + g_free(sim->pending); > + sim->pending = NULL; > +} > + > +static void handle_gsm(struct ofono_sim_auth *sim, const uint8_t *resp, > + uint16_t len) > +{ > + DBusMessageIter iter; > + const uint8_t *sres = NULL; > + const uint8_t *kc = NULL; > + > + if (!sim_parse_gsm_authenticate(resp, len, &sres, &kc)) > + goto gsm_end; > + > + /* initial iteration, setup the reply message */ > + if (sim->pending->cb_count == 0) { > + sim->pending->reply = dbus_message_new_method_return( > + sim->pending->msg); > + > + dbus_message_iter_init_append(sim->pending->reply, > + &sim->pending->iter); > + > + dbus_message_iter_open_container(&sim->pending->iter, > + DBUS_TYPE_ARRAY, "a{say}", &sim->pending->dict); > + } > + > + /* append the Nth sres/kc byte arrays */ > + dbus_message_iter_open_container(&sim->pending->dict, DBUS_TYPE_ARRAY, > + "{say}", &iter); > + append_dict_byte_array(&iter, "SRES", sres, 4); > + append_dict_byte_array(&iter, "Kc", kc, 8); > + dbus_message_iter_close_container(&sim->pending->dict, &iter); > + > + sim->pending->cb_count++; > + > + /* calculated the number of keys requested, close container */ > + if (sim->pending->cb_count == sim->pending->num_rands) { > + dbus_message_iter_close_container(&sim->pending->iter, > + &sim->pending->dict); > + goto gsm_end; > + } > + > + return; > + > +gsm_end: > + if (!sim->pending->reply) > + sim->pending->reply = __ofono_error_not_supported( > + sim->pending->msg); > + > + __ofono_dbus_pending_reply(&sim->pending->msg, sim->pending->reply); > + > + sim->driver->close_channel(sim, sim->pending->session_id, NULL, NULL); > + > + g_free(sim->pending); > + > + sim->pending = NULL; > +} > + > +static void logical_access_cb(const struct ofono_error *error, > + const uint8_t *resp, uint16_t len, void *data) > +{ > + struct ofono_sim_auth *sim = data; > + You trigger this 2-3 times (num_rands) in a row in the case of GSM. If one of the callbacks results in an error, what happens to the subsequent callbacks (sim->pending has been freed at this point) ? > + if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { > + __ofono_dbus_pending_reply(&sim->pending->msg, > + __ofono_error_failed(sim->pending->msg)); > + g_free(sim->pending); > + sim->pending = NULL; > + return; > + } > + > + if (sim->pending->umts) > + handle_umts(sim, resp, len); > + else > + handle_gsm(sim, resp, len); > +} > + > +static void open_channel_cb(const struct ofono_error *error, int session_id, > + void *data) > +{ > + struct ofono_sim_auth *sim = data; > + int i; > + > + if (error->type != OFONO_ERROR_TYPE_NO_ERROR) > + goto error; > + > + if (session_id == -1) > + goto error; > + > + /* save session ID for close_channel() */ > + sim->pending->session_id = session_id; > + > + /* > + * This will do the logical access num_rand times, providing a new > + * RAND seed each time. In the UMTS case, num_rands should be 1. > + */ > + for (i = 0; i < sim->pending->num_rands; i++) { > + uint8_t auth_cmd[40]; > + int len = 0; > + > + if (sim->pending->umts) > + len = sim_build_umts_authenticate(auth_cmd, 40, > + sim->pending->rands[i], > + sim->pending->autn); > + else > + len = sim_build_gsm_authenticate(auth_cmd, 40, > + sim->pending->rands[i]); > + > + if (!len) > + goto error; > + > + sim->driver->logical_access(sim, session_id, auth_cmd, len, > + logical_access_cb, sim); > + } > + > + return; > + > +error: > + __ofono_dbus_pending_reply(&sim->pending->msg, > + __ofono_error_failed(sim->pending->msg)); > + g_free(sim->pending); > + sim->pending = NULL; > +} > + > +static DBusMessage *usim_gsm_authenticate(DBusConnection *conn, > + DBusMessage *msg, void *data) > +{ > + struct ofono_sim_auth *sim = data; > + DBusMessageIter iter; > + DBusMessageIter array; > + int i; > + struct sim_app_record *app; > + > + if (sim->pending) > + return __ofono_error_busy(msg); > + > + dbus_message_iter_init(msg, &iter); > + > + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) > + return __ofono_error_not_supported(msg); > + > + sim->pending = malloc(sizeof(struct auth_request)); > + sim->pending->msg = dbus_message_ref(msg); > + sim->pending->umts = 0; > + sim->pending->cb_count = 0; > + sim->pending->num_rands = dbus_message_iter_get_element_count(&iter); > + > + dbus_message_iter_recurse(&iter, &array); > + > + for (i = 0; i < sim->pending->num_rands; i++) { > + int nelement; > + DBusMessageIter in; > + > + dbus_message_iter_recurse(&array, &in); > + > + dbus_message_iter_get_fixed_array(&in, &sim->pending->rands[i], > + &nelement); Do we need a sanity check that rand is 16 bytes? > + dbus_message_iter_next(&array); > + } > + > + app = find_aid_by_path(sim->aid_list, dbus_message_get_path(msg)); > + > + sim->driver->open_channel(sim, app->aid, open_channel_cb, sim); > + > + return NULL; > +} > + > +static DBusMessage *umts_common(DBusConnection *conn, DBusMessage *msg, > + void *data, enum sim_app_type type) > +{ > + uint8_t *rand = NULL; > + uint8_t *autn = NULL; > + uint32_t rlen; > + uint32_t alen; > + struct ofono_sim_auth *sim = data; > + struct sim_app_record *app; > + > + if (sim->pending) > + return __ofono_error_busy(msg); > + > + /* get RAND/AUTN and setup handle args */ > + dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY, > + DBUS_TYPE_BYTE, &rand, &rlen, DBUS_TYPE_ARRAY, > + DBUS_TYPE_BYTE, &autn, &alen, > + DBUS_TYPE_INVALID); The return of this method call needs to be checked in case the sent message signature doesn't match. > + > + if (rlen != 16 || alen != 16) { > + g_free(sim->pending); > + sim->pending = NULL; You haven't created sim->pending yet? > + return __ofono_error_invalid_args(msg); This likely should be _invalid_format > + } > + > + sim->pending = g_new0(struct auth_request, 1); > + sim->pending->msg = dbus_message_ref(msg); > + sim->pending->rands[0] = rand; > + sim->pending->num_rands = 1; > + sim->pending->autn = autn; > + sim->pending->umts = 1; > + > + app = find_aid_by_path(sim->aid_list, dbus_message_get_path(msg)); > + > + sim->driver->open_channel(sim, app->aid, open_channel_cb, sim); > + > + return NULL; > +} > + > +static DBusMessage *get_applications(DBusConnection *conn, > + DBusMessage *msg, void *data) > +{ > + struct ofono_sim_auth *sim = data; > + const char *path = __ofono_atom_get_path(sim->atom); > + int ret; > + char object[strlen(path) + 33]; > + DBusMessage *reply; > + DBusMessageIter iter; > + DBusMessageIter array; > + DBusMessageIter dict; > + GSList *aid_iter; > + > + if (!sim->aid_list) > + return __ofono_error_busy(msg); If it is NULL then an empty list should be returned. Remember we register D-Bus interface only after discovery has been performed, so get_applications won't be called until then. > + > + reply = dbus_message_new_method_return(msg); > + if (reply == NULL) > + return NULL; > + > + dbus_message_iter_init_append(reply, &iter); > + > + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{oa{sv}}", > + &array); > + > + aid_iter = sim->aid_list; > + > + while (aid_iter) { > + struct sim_app_record *app = aid_iter->data; > + > + ret = sprintf(object, "%s/", path); > + encode_hex_own_buf(app->aid, 16, 0, object + ret); > + > + switch (app->type) { > + case SIM_APP_TYPE_ISIM: > + dbus_message_iter_open_container(&array, > + DBUS_TYPE_DICT_ENTRY, NULL, &dict); > + append_dict_application(&dict, object, "Ims", "ISim"); > + dbus_message_iter_close_container(&array, &dict); > + > + break; > + case SIM_APP_TYPE_USIM: > + dbus_message_iter_open_container(&array, > + DBUS_TYPE_DICT_ENTRY, NULL, &dict); > + append_dict_application(&dict, object, "Umts", "USim"); > + dbus_message_iter_close_container(&array, &dict); > + > + break; > + default: > + break; > + } > + > + aid_iter = g_slist_next(aid_iter); > + } > + > + dbus_message_iter_close_container(&iter, &array); > + > + return reply; > +} > + > +static DBusMessage *send_properties(DBusConnection *conn, DBusMessage *msg, > + void *data, const char *type, const char *name) > +{ > + DBusMessage *reply; > + DBusMessageIter iter; > + DBusMessageIter array; > + > + reply = dbus_message_new_method_return(msg); > + if (reply == NULL) > + return NULL; > + > + dbus_message_iter_init_append(reply, &iter); > + > + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", > + &array); > + > + ofono_dbus_dict_append(&array, "Type", DBUS_TYPE_STRING, &type); > + ofono_dbus_dict_append(&array, "Name", DBUS_TYPE_STRING, &name); > + > + dbus_message_iter_close_container(&iter, &array); > + > + return reply; > +} > + > +static DBusMessage *usim_get_properties(DBusConnection *conn, > + DBusMessage *msg, void *data) > +{ > + return send_properties(conn, msg, data, "Umts", "USim"); > +} > + > +static DBusMessage *isim_get_properties(DBusConnection *conn, > + DBusMessage *msg, void *data) > +{ > + return send_properties(conn, msg, data, "Ims", "ISim"); > +} > + > +static DBusMessage *isim_ims_authenticate(DBusConnection *conn, > + DBusMessage *msg, void *data) > +{ > + return umts_common(conn, msg, data, SIM_APP_TYPE_ISIM); > +} > + > +static DBusMessage *usim_umts_authenticate(DBusConnection *conn, > + DBusMessage *msg, void *data) > +{ > + return umts_common(conn, msg, data, SIM_APP_TYPE_USIM); > +} > + > +static const GDBusMethodTable sim_authentication[] = { > + { GDBUS_METHOD("GetApplications", > + NULL, > + GDBUS_ARGS({"applications", "a{oa{sv}}"}), > + get_applications) }, > + { } > +}; > + > +static const GDBusMethodTable sim_auth_usim_app[] = { > + { GDBUS_ASYNC_METHOD("GetProperties", > + NULL, > + GDBUS_ARGS({"properties", "a{sv}"}), > + usim_get_properties) }, > + { GDBUS_ASYNC_METHOD("GsmAuthenticate", > + GDBUS_ARGS({"rands", "aay"}), > + GDBUS_ARGS({"keys", "a{say}"}), > + usim_gsm_authenticate) }, > + { GDBUS_ASYNC_METHOD("UmtsAuthenticate", > + GDBUS_ARGS({"rand", "ay"}, {"autn", "ay"}), > + GDBUS_ARGS({"return", "a{sv}"}), > + usim_umts_authenticate) }, > + { } > +}; > + > +static const GDBusMethodTable sim_auth_isim_app[] = { > + { GDBUS_ASYNC_METHOD("GetProperties", > + NULL, > + GDBUS_ARGS({"properties", "a{sv}"}), > + isim_get_properties) }, > + { GDBUS_ASYNC_METHOD("ImsAuthenticate", > + GDBUS_ARGS({"rand", "ay"}, {"autn", "ay"}), > + GDBUS_ARGS({"return", "a{sv}"}), > + isim_ims_authenticate) }, > + { } > +}; > + > +static void discover_apps_cb(const struct ofono_error *error, > + const unsigned char *dataobj, > + int len, void *data) > +{ > + DBusConnection *conn = ofono_dbus_get_connection(); > + struct ofono_sim_auth *sim = data; > + struct ofono_modem *modem = __ofono_atom_get_modem(sim->atom); > + const char *path = __ofono_atom_get_path(sim->atom); > + GSList *iter; > + char app_path[strlen(path) + 34]; > + int ret; > + > + if (error->type != OFONO_ERROR_TYPE_NO_ERROR) > + goto parse_error; > + > + sim->aid_list = sim_parse_app_template_entries(dataobj, len); > + > + if (!sim->aid_list) > + goto parse_error; > + > + iter = sim->aid_list; > + > + ret = sprintf(app_path, "%s/", path); > + > + while (iter) { > + struct sim_app_record *app = iter->data; > + > + switch (app->type) { > + case SIM_APP_TYPE_USIM: > + encode_hex_own_buf(app->aid, 16, 0, app_path + ret); > + > + app_path[ret + 32] = '\0'; encode_hex_own_buf already null terminates the buffer, so this isn't needed > + > + g_dbus_register_interface(conn, app_path, > + OFONO_USIM_APPLICATION_INTERFACE, > + sim_auth_usim_app, NULL, NULL, > + sim, NULL); > + break; > + case SIM_APP_TYPE_ISIM: > + encode_hex_own_buf(app->aid, 16, 0, app_path + ret); > + > + app_path[ret + 32] = '\0'; > + as above > + g_dbus_register_interface(conn, app_path, > + OFONO_ISIM_APPLICATION_INTERFACE, > + sim_auth_isim_app, NULL, NULL, > + sim, NULL); > + break; > + default: > + DBG("Unknown SIM application '%04x'", app->type); > + /* > + * If we get here, the SIM application was not ISIM > + * or USIM, skip. > + */ > + } > + > + iter = g_slist_next(iter); > + } > + > + /* > + * Now SimAuthentication interface can be registered since app > + * discovery has completed > + */ > + g_dbus_register_interface(conn, path, > + OFONO_SIM_AUTHENTICATION_INTERFACE, > + sim_authentication, NULL, NULL, > + sim, NULL); > + ofono_modem_add_interface(modem, > + OFONO_SIM_AUTHENTICATION_INTERFACE); > + > + return; > + > +parse_error: > + /* > + * Something went wrong parsing the AID list, it can't be assumed that > + * any previously parsed AID's are valid so free them all. > + */ > + DBG("Error parsing app list"); > +} > + > void ofono_sim_auth_register(struct ofono_sim_auth *sa) > { > + struct ofono_modem *modem = __ofono_atom_get_modem(sa->atom); > + > __ofono_atom_register(sa->atom, sim_auth_unregister); > + > + /* Do SIM application discovery, the cb will register DBus ifaces */ > + sa->driver->list_apps(sa, discover_apps_cb, sa); > + > + sa->sim = __ofono_atom_find(OFONO_ATOM_TYPE_SIM, modem); > + > + sa->gsm_access = __ofono_sim_ust_service_available(sa->sim, > + SIM_UST_SERVICE_GSM_ACCESS); > + sa->gsm_context = __ofono_sim_ust_service_available(sa->sim, > + SIM_UST_SERVICE_GSM_SECURITY_CONTEXT); > } > > void ofono_sim_auth_remove(struct ofono_sim_auth *sa) > Regards, -Denis ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2017-10-12 14:54 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-10-11 23:22 [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom James Prestwood 2017-10-11 23:22 ` [PATCHv4 2/6] atmodem: implemented sim-auth functionality in atmodem James Prestwood 2017-10-11 23:22 ` [PATCHv4 3/6] xmm7xxx: add sim-auth driver to xmm7xxx plugin James Prestwood 2017-10-12 14:53 ` Denis Kenzior 2017-10-11 23:22 ` [PATCHv4 4/6] phonesim: Added sim-auth to phonesim plugin James Prestwood 2017-10-12 14:54 ` Denis Kenzior 2017-10-11 23:22 ` [PATCHv4 5/6] test: added tests for GSM/UMTS auth algorithms James Prestwood 2017-10-12 14:52 ` Denis Kenzior 2017-10-11 23:22 ` [PATCHv4 6/6] doc: documentation for SimAuth dbus interfaces James Prestwood 2017-10-12 14:51 ` Denis Kenzior 2017-10-12 14:48 ` [PATCHv4 1/6] sim-auth: implementation of core sim-auth atom Denis Kenzior
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox