diff options
author | Dr. David Alan Gilbert <dave@treblig.org> | 2017-01-02 16:10:14 +0000 |
---|---|---|
committer | Dr. David Alan Gilbert <dave@treblig.org> | 2018-02-25 02:08:49 +0000 |
commit | 77a487c7eedfef3104835d09044e71939b5dcbfa (patch) | |
tree | 10143721e8eecd29d1d6bcfe041474dc7ec64af6 | |
parent | 08b25e67e6e7189e4ba268ffe9326071adccc5e1 (diff) | |
download | purple-matrix-77a487c7eedfef3104835d09044e71939b5dcbfa.tar.gz |
e2e: Retrieve or create Olm account state, send keys
If we've got a previously stored olm account state then use it,
else create us a new one.
Either way, upload the device keys to the server.
Signed-off-by: Dr. David Alan Gilbert <dave@treblig.org>
-rw-r--r-- | matrix-connection.c | 10 | ||||
-rw-r--r-- | matrix-e2e.c | 159 | ||||
-rw-r--r-- | matrix-e2e.h | 3 |
3 files changed, 170 insertions, 2 deletions
diff --git a/matrix-connection.c b/matrix-connection.c index 91c660a..736782b 100644 --- a/matrix-connection.c +++ b/matrix-connection.c @@ -17,6 +17,7 @@ */ #include "matrix-connection.h" +#include "matrix-e2e.h" #include <string.h> @@ -53,6 +54,7 @@ void matrix_connection_free(PurpleConnection *pc) g_assert(conn != NULL); + matrix_e2e_cleanup_connection(conn); purple_connection_set_protocol_data(pc, NULL); g_free(conn->homeserver); @@ -167,6 +169,7 @@ static void _login_completed(MatrixConnectionData *conn, JsonObject *root_obj; const gchar *access_token; const gchar *next_batch; + const gchar *device_id; gboolean needs_full_state_sync = TRUE; root_obj = matrix_json_node_get_object(json_root); @@ -181,9 +184,12 @@ static void _login_completed(MatrixConnectionData *conn, conn->access_token = g_strdup(access_token); conn->user_id = g_strdup(matrix_json_object_get_string_member(root_obj, "user_id")); - purple_account_set_string(pc->account, "device_id", - matrix_json_object_get_string_member(root_obj, "device_id")); + device_id = matrix_json_object_get_string_member(root_obj, "device_id"); + purple_account_set_string(pc->account, "device_id", device_id); + if (device_id) { + matrix_e2e_get_device_keys(conn, device_id); + } /* start the sync loop */ next_batch = purple_account_get_string(pc->account, PRPL_ACCOUNT_OPT_NEXT_BATCH, NULL); diff --git a/matrix-e2e.c b/matrix-e2e.c index 792c580..c4c2cfa 100644 --- a/matrix-e2e.c +++ b/matrix-e2e.c @@ -34,6 +34,8 @@ struct _MatrixE2EData { OlmAccount *oa; gchar *device_id; + gchar *curve25519_pubkey; + gchar *ed25519_pubkey; }; /* Really clear an area of memory */ @@ -296,6 +298,163 @@ static int get_id_keys(PurpleConnection *pc, OlmAccount *account, gchar ***algor return n_keys; } +static void key_upload_callback(MatrixConnectionData *conn, + gpointer user_data, + struct _JsonNode *json_root, + const char *body, + size_t body_len, const char *content_type) +{ + // TODO +} + +/* + * Get a set of device keys for ourselves. Either by retreiving it from our store + * or by generating a new set. + * + * Returns: 0 on success + */ +int matrix_e2e_get_device_keys(MatrixConnectionData *conn, const gchar *device_id) +{ + PurpleConnection *pc = conn->pc; + JsonObject * json_dev_keys = NULL; + OlmAccount *account = olm_account(g_malloc0(olm_account_size())); + char *pickled_account = NULL; + void *random_pot = NULL; + int ret = 0; + + if (!conn->e2e) { + conn->e2e = g_new0(MatrixE2EData,1); + conn->e2e->device_id = g_strdup(device_id); + } + conn->e2e->oa = account; + + /* Try and restore olm account from settings; may fail, may work + * or may say there were no settings stored. + */ + ret = matrix_restore_e2e_account(conn); + purple_debug_info("matrixprpl", + "restore_e2e_account says %d\n", ret); + if (ret < 0) { + goto out; + } + + if (ret == 0) { + /* No stored account - create one */ + size_t needed_random = olm_create_account_random_length(account); + random_pot = get_random(needed_random); + if (!random_pot) { + purple_connection_error_reason(pc, + PURPLE_CONNECTION_ERROR_OTHER_ERROR, + "Unable to get randomness"); + ret = -1; + goto out; + }; + + if (olm_create_account(account, random_pot, needed_random) == + olm_error()) { + purple_connection_error_reason(pc, + PURPLE_CONNECTION_ERROR_OTHER_ERROR, + olm_account_last_error(account)); + ret = -1; + goto out; + } + ret = matrix_store_e2e_account(conn); + if (ret) { + goto out; + } + } + + /* Form a device keys object for an upload, + * from https://matrix.org/speculator/spec/drafts%2Fe2e/client_server/unstable.html#post-matrix-client-unstable-keys-upload + */ + json_dev_keys = json_object_new(); + json_object_set_string_member(json_dev_keys, "user_id", conn->user_id); + json_object_set_string_member(json_dev_keys, "device_id", device_id); + /* Add 'algorithms' array - is there a way to get libolm to tell us the list of what's supported */ + /* the output of olm_account_identity_keys isn't quite right for it */ + JsonArray *algorithms = json_array_new(); + json_array_add_string_element(algorithms, "m.olm.curve25519-aes-sha256"); + json_array_add_string_element(algorithms, "m.megolm.v1.aes-sha"); + json_object_set_array_member(json_dev_keys, "algorithms", algorithms); + + /* Add 'keys' entry */ + JsonObject *json_keys = json_object_new(); + gchar **algorithm_strings, **key_strings; + int num_algorithms = get_id_keys(pc, account, &algorithm_strings, + &key_strings); + if (num_algorithms < 1) { + json_object_unref(json_keys); + goto out; + } + + int alg; + + for(alg = 0; alg < num_algorithms; alg++) { + GString *algdev = g_string_new(NULL); + g_string_printf(algdev, "%s:%s", algorithm_strings[alg], device_id); + gchar *alg_dev_char = g_string_free(algdev, FALSE); + json_object_set_string_member(json_keys, alg_dev_char, + key_strings[alg]); + + if (!strcmp(algorithm_strings[alg], "curve25519")) { + conn->e2e->curve25519_pubkey = key_strings[alg]; + } else if (!strcmp(algorithm_strings[alg], "ed25519")) { + conn->e2e->ed25519_pubkey = key_strings[alg]; + } else { + g_free(key_strings[alg]); + } + g_free(algorithm_strings[alg]); + g_free(alg_dev_char); + } + g_free(algorithm_strings); + g_free(key_strings); + json_object_set_object_member(json_dev_keys, "keys", json_keys); + + /* Sign */ + if (matrix_sign_json(conn, json_dev_keys)) { + goto out; + } + + /* Send the keys */ + matrix_api_upload_keys(conn, json_dev_keys, NULL /* TODO: one time keys */, + key_upload_callback, + matrix_api_error, matrix_api_bad_response, (void *)0); + json_dev_keys = NULL; /* api_upload_keys frees it with it's whole json */ + + ret = 0; + +out: + if (json_dev_keys) + json_object_unref(json_dev_keys); + g_free(pickled_account); + g_free(random_pot); + + if (ret) { + matrix_e2e_cleanup_connection(conn); + } + return ret; +} + +void matrix_e2e_cleanup_connection(MatrixConnectionData *conn) +{ + if (conn->e2e) { + g_free(conn->e2e->curve25519_pubkey); + g_free(conn->e2e->oa); + g_free(conn->e2e->device_id); + g_free(conn->e2e); + conn->e2e = NULL; + } +} + #else /* ==== Stubs for when e2e is configured out of the build === */ +int matrix_e2e_get_device_keys(MatrixConnectionData *conn, const gchar *device_id) +{ + return -1; +} + +void matrix_e2e_cleanup_connection(MatrixConnectionData *conn) +{ +} + #endif diff --git a/matrix-e2e.h b/matrix-e2e.h index 1ac190a..48afca3 100644 --- a/matrix-e2e.h +++ b/matrix-e2e.h @@ -23,4 +23,7 @@ typedef struct _MatrixE2EData MatrixE2EData; +int matrix_e2e_get_device_keys(MatrixConnectionData *conn, const gchar *device_id); +void matrix_e2e_cleanup_connection(MatrixConnectionData *conn); + #endif |