aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. David Alan Gilbert <dave@treblig.org>2017-02-12 17:49:08 +0000
committerDr. David Alan Gilbert <dave@treblig.org>2018-02-25 02:08:49 +0000
commitbd33bb94bcc1f8bd615099fd1269056c36b4a24b (patch)
tree6cab6b0a4daaafd82dafdcef738a5c74412758c9
parente23ec6e50b6ff755668e8bbca362e42958c9eaef (diff)
downloadpurple-matrix-bd33bb94bcc1f8bd615099fd1269056c36b4a24b.tar.gz
e2e: Create and send one time keys
Signed-off-by: Dr. David Alan Gilbert <dave@treblig.org>
-rw-r--r--matrix-e2e.c120
1 files changed, 119 insertions, 1 deletions
diff --git a/matrix-e2e.c b/matrix-e2e.c
index f12c19f..e263c17 100644
--- a/matrix-e2e.c
+++ b/matrix-e2e.c
@@ -38,6 +38,12 @@ struct _MatrixE2EData {
gchar *ed25519_pubkey;
};
+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);
+
/* Really clear an area of memory */
static void clear_mem(volatile char *data, size_t len)
{
@@ -298,6 +304,118 @@ static int get_id_keys(PurpleConnection *pc, OlmAccount *account, gchar ***algor
return n_keys;
}
+/* See: https://matrix.org/docs/guides/e2e_implementation.html#creating-and-registering-one-time-keys */
+static int send_one_time_keys(MatrixConnectionData *conn, size_t n_keys)
+{
+ PurpleConnection *pc = conn->pc;
+ int ret;
+ size_t random_needed;
+ void *random_buffer;
+ void *olm_1t_keys_json = NULL;
+ JsonParser *json_parser = NULL;
+ size_t olm_keys_buffer_size;
+ JsonObject *otk_json = NULL;
+ random_needed = olm_account_generate_one_time_keys_random_length(
+ conn->e2e->oa, n_keys);
+ random_buffer = get_random(random_needed);
+ if (!random_buffer) {
+ return -1;
+ }
+
+ if (olm_account_generate_one_time_keys(conn->e2e->oa, n_keys, random_buffer,
+ random_needed) == olm_error()) {
+ purple_connection_error_reason(pc,
+ PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+ olm_account_last_error(conn->e2e->oa));
+ ret = -1;
+ goto out;
+ }
+
+ olm_keys_buffer_size = olm_account_one_time_keys_length(conn->e2e->oa);
+ olm_1t_keys_json = g_malloc0(olm_keys_buffer_size+1);
+ if (olm_account_one_time_keys(conn->e2e->oa, olm_1t_keys_json,
+ olm_keys_buffer_size) == olm_error()) {
+ purple_connection_error_reason(pc,
+ PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+ olm_account_last_error(conn->e2e->oa));
+ ret = -1;
+ goto out;
+ }
+
+ /* olm_1t_keys_json has json like:
+ * {
+ * curve25519: {
+ * "keyid1": "base64encodedcurve25519key1",
+ * "keyid2": "base64encodedcurve25519key2"
+ * }
+ * }
+ * I think in practice this is just curve25519 but I'll avoid hard coding
+ * We need to produce an object with a set of signed objects each having
+ * one key
+ */
+ json_parser = json_parser_new();
+ GError *err = NULL;
+ if (!json_parser_load_from_data(json_parser,
+ olm_1t_keys_json, strlen(olm_1t_keys_json), &err)) {
+ purple_connection_error_reason(pc,
+ PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+ "Failed to parse generated 1-time json");
+ g_error_free(err);
+ ret = -1;
+ goto out;
+ }
+
+ /* The output JSON we're generating */
+ otk_json = json_object_new();
+
+ JsonNode *olm_1tk_root = json_parser_get_root(json_parser);
+ JsonObject *olm_1tk_obj = matrix_json_node_get_object(olm_1tk_root);
+ JsonObjectIter algo_iter;
+ json_object_iter_init(&algo_iter, olm_1tk_obj);
+ const gchar *keys_algo;
+ JsonNode *keys_node;
+ while (json_object_iter_next(&algo_iter, &keys_algo, &keys_node)) {
+ /* We're expecting keys_algo to be "curve25519" and keys_node to be an
+ * object with a set of keys.
+ */
+ JsonObjectIter keys_iter;
+ JsonObject *keys_obj = matrix_json_node_get_object(keys_node);
+ json_object_iter_init(&keys_iter, keys_obj);
+ const gchar *key_id;
+ JsonNode *key_node;
+ while (json_object_iter_next(&keys_iter, &key_id, &key_node)) {
+ const gchar *key_string = matrix_json_node_get_string(key_node);
+
+ JsonObject *signed_key = json_object_new();
+ json_object_set_string_member(signed_key, "key", key_string);
+ ret = matrix_sign_json(conn, signed_key);
+ if (ret) {
+ g_object_unref(signed_key);
+ goto out;
+ }
+ gchar *signed_key_name = g_strdup_printf("signed_%s:%s", keys_algo,
+ key_id);
+ json_object_set_object_member(otk_json,
+ signed_key_name, signed_key);
+ g_free(signed_key_name);
+ }
+ }
+
+ matrix_api_upload_keys(conn, NULL, otk_json,
+ key_upload_callback,
+ matrix_api_error, matrix_api_bad_response, (void *)1);
+ otk_json = NULL; /* matrix_api_upload_keys frees with its json */
+ ret = 0;
+out:
+ g_object_unref(json_parser);
+ if (otk_json)
+ g_object_unref(otk_json);
+ g_free(random_buffer);
+ g_free(olm_1t_keys_json);
+
+ return ret;
+}
+
/* Called from sync with an object of the form:
* "device_one_time_keys_count" : {
* "signed_curve25519" : 100
@@ -332,7 +450,7 @@ void matrix_e2e_handle_sync_key_counts(PurpleConnection *pc, JsonObject *count_o
need_to_send |= !valid_counts;
if (need_to_send) {
purple_debug_info("matrixprpl", "%s: need to send\n",__func__);
- // TODO send_one_time_keys(conn, to_create);
+ send_one_time_keys(conn, to_create);
}
}