diff options
author | Dr. David Alan Gilbert <dave@treblig.org> | 2017-02-12 17:49:08 +0000 |
---|---|---|
committer | Dr. David Alan Gilbert <dave@treblig.org> | 2018-02-25 02:08:49 +0000 |
commit | bd33bb94bcc1f8bd615099fd1269056c36b4a24b (patch) | |
tree | 6cab6b0a4daaafd82dafdcef738a5c74412758c9 /matrix-e2e.c | |
parent | e23ec6e50b6ff755668e8bbca362e42958c9eaef (diff) | |
download | purple-matrix-bd33bb94bcc1f8bd615099fd1269056c36b4a24b.tar.gz |
e2e: Create and send one time keys
Signed-off-by: Dr. David Alan Gilbert <dave@treblig.org>
Diffstat (limited to 'matrix-e2e.c')
-rw-r--r-- | matrix-e2e.c | 120 |
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); } } |