[epiphany/wip/sync: 67/86] sync: Get the per-collection sync keys too, if any



commit 163763065b09403255fa9a1c98378a38ce8e17c2
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Sat Mar 11 01:20:08 2017 +0200

    sync: Get the per-collection sync keys too, if any

 src/sync/ephy-sync-crypto.c  |   51 +++++++++++++++++++++++++++++
 src/sync/ephy-sync-crypto.h  |    8 ++++
 src/sync/ephy-sync-service.c |   73 ++++++++++++++++++-----------------------
 src/sync/ephy-sync-utils.c   |    8 ----
 src/sync/ephy-sync-utils.h   |    4 +--
 5 files changed, 92 insertions(+), 52 deletions(-)
---
diff --git a/src/sync/ephy-sync-crypto.c b/src/sync/ephy-sync-crypto.c
index 06d51e2..a070f5c 100644
--- a/src/sync/ephy-sync-crypto.c
+++ b/src/sync/ephy-sync-crypto.c
@@ -176,6 +176,57 @@ ephy_sync_crypto_rsa_key_pair_free (SyncCryptoRSAKeyPair *keypair)
   g_slice_free (SyncCryptoRSAKeyPair, keypair);
 }
 
+static SyncCryptoKeyBundle *
+ephy_sync_crypto_key_bundle_new (const char *aes_key_hex,
+                                 const char *hmac_key_hex)
+{
+  SyncCryptoKeyBundle *bundle;
+
+  bundle = g_slice_new (SyncCryptoKeyBundle);
+  bundle->aes_key_hex = g_strdup (aes_key_hex);
+  bundle->hmac_key_hex = g_strdup (hmac_key_hex);
+
+  return bundle;
+}
+
+SyncCryptoKeyBundle *
+ephy_sync_crypto_key_bundle_from_array (JsonArray *array)
+{
+  SyncCryptoKeyBundle *bundle;
+  char *aes_key_hex;
+  char *hmac_key_hex;
+  guint8 *aes_key;
+  guint8 *hmac_key;
+  gsize len;
+
+  g_return_val_if_fail (array, NULL);
+  g_return_val_if_fail (json_array_get_length (array) == 2, NULL);
+
+  aes_key = g_base64_decode (json_array_get_string_element (array, 0), &len);
+  hmac_key = g_base64_decode (json_array_get_string_element (array, 1), &len);
+  aes_key_hex = ephy_sync_crypto_encode_hex (aes_key, 0);
+  hmac_key_hex = ephy_sync_crypto_encode_hex (hmac_key, 0);
+  bundle = ephy_sync_crypto_key_bundle_new (aes_key_hex, hmac_key_hex);
+
+  g_free (aes_key);
+  g_free (hmac_key);
+  g_free (aes_key_hex);
+  g_free (hmac_key_hex);
+
+  return bundle;
+}
+
+void
+ephy_sync_crypto_key_bundle_free (SyncCryptoKeyBundle *bundle)
+{
+  g_return_if_fail (bundle);
+
+  g_free (bundle->aes_key_hex);
+  g_free (bundle->hmac_key_hex);
+
+  g_slice_free (SyncCryptoKeyBundle, bundle);
+}
+
 static char *
 ephy_sync_crypto_kw (const char *name)
 {
diff --git a/src/sync/ephy-sync-crypto.h b/src/sync/ephy-sync-crypto.h
index 334bf71..a7e0b85 100644
--- a/src/sync/ephy-sync-crypto.h
+++ b/src/sync/ephy-sync-crypto.h
@@ -21,6 +21,7 @@
 #pragma once
 
 #include <glib-object.h>
+#include <json-glib/json-glib.h>
 #include <nettle/rsa.h>
 
 G_BEGIN_DECLS
@@ -67,6 +68,11 @@ typedef struct {
   struct rsa_private_key private;
 } SyncCryptoRSAKeyPair;
 
+typedef struct {
+  char *aes_key_hex;
+  char *hmac_key_hex;
+} SyncCryptoKeyBundle;
+
 SyncCryptoHawkOptions  *ephy_sync_crypto_hawk_options_new         (const char             *app,
                                                                    const char             *dlg,
                                                                    const char             *ext,
@@ -79,6 +85,8 @@ SyncCryptoHawkOptions  *ephy_sync_crypto_hawk_options_new         (const char
 void                    ephy_sync_crypto_hawk_options_free        (SyncCryptoHawkOptions  *options);
 void                    ephy_sync_crypto_hawk_header_free         (SyncCryptoHawkHeader   *header);
 void                    ephy_sync_crypto_rsa_key_pair_free        (SyncCryptoRSAKeyPair   *keypair);
+SyncCryptoKeyBundle    *ephy_sync_crypto_key_bundle_from_array    (JsonArray              *array);
+void                    ephy_sync_crypto_key_bundle_free          (SyncCryptoKeyBundle    *bundle);
 void                    ephy_sync_crypto_process_key_fetch_token  (const char             *keyFetchToken,
                                                                    guint8                **tokenID,
                                                                    guint8                **reqHMACkey,
diff --git a/src/sync/ephy-sync-service.c b/src/sync/ephy-sync-service.c
index 759fde1..9103bde 100644
--- a/src/sync/ephy-sync-service.c
+++ b/src/sync/ephy-sync-service.c
@@ -52,8 +52,7 @@ struct _EphySyncService {
   char        *uid;
   char        *sessionToken;
   char        *kB;
-  char        *default_aes_key;
-  char        *default_hmac_key;
+  GHashTable  *key_bundles;
 
   char        *user_email;
   double       sync_time;
@@ -614,6 +613,7 @@ ephy_sync_service_finalize (GObject *object)
     ephy_sync_crypto_rsa_key_pair_free (self->keypair);
 
   g_queue_free_full (self->storage_queue, (GDestroyNotify) storage_server_request_async_data_free);
+  g_hash_table_destroy (self->key_bundles);
 
   G_OBJECT_CLASS (ephy_sync_service_parent_class)->finalize (object);
 }
@@ -676,6 +676,8 @@ ephy_sync_service_init (EphySyncService *self)
 
   self->session = soup_session_new ();
   self->storage_queue = g_queue_new ();
+  self->key_bundles = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                             NULL, (GDestroyNotify)ephy_sync_crypto_key_bundle_free);
 
   settings = ephy_embed_prefs_get_settings ();
   user_agent = webkit_settings_get_user_agent (settings);
@@ -759,10 +761,6 @@ ephy_sync_service_get_token (EphySyncService   *self,
       return self->sessionToken;
     case TOKEN_KB:
       return self->kB;
-    case TOKEN_DEFAULT_AES_KEY:
-      return self->default_aes_key;
-    case TOKEN_DEFAULT_HMAC_KEY:
-      return self->default_hmac_key;
     default:
       g_assert_not_reached ();
   }
@@ -789,14 +787,6 @@ ephy_sync_service_set_token (EphySyncService   *self,
       g_free (self->kB);
       self->kB = g_strdup (value);
       break;
-    case TOKEN_DEFAULT_AES_KEY:
-      g_free (self->default_aes_key);
-      self->default_aes_key = g_strdup (value);
-      break;
-    case TOKEN_DEFAULT_HMAC_KEY:
-      g_free (self->default_hmac_key);
-      self->default_hmac_key = g_strdup (value);
-      break;
     default:
       g_assert_not_reached ();
   }
@@ -822,8 +812,6 @@ ephy_sync_service_clear_tokens (EphySyncService *self)
   g_clear_pointer (&self->uid, g_free);
   g_clear_pointer (&self->sessionToken, g_free);
   g_clear_pointer (&self->kB, g_free);
-  g_clear_pointer (&self->default_aes_key, g_free);
-  g_clear_pointer (&self->default_hmac_key, g_free);
 }
 
 static void
@@ -904,27 +892,26 @@ ephy_sync_service_report_sign_in_error (EphySyncService *self,
 }
 
 static void
-obtain_default_sync_keys_cb (SoupSession *session,
-                             SoupMessage *msg,
-                             gpointer     user_data)
+obtain_sync_key_bundles (SoupSession *session,
+                         SoupMessage *msg,
+                         gpointer     user_data)
 {
   EphySyncService *service;
   JsonParser *parser;
   JsonObject *json;
+  JsonObject *collections;
+  JsonNode *node;
   JsonArray *array;
+  JsonObjectIter iter;
   const char *ciphertext_b64;
   const char *iv_b64;
   const char *hmac;
+  const char *member;
   char *payload;
   char *record;
-  char *default_aes_key_hex;
-  char *default_hmac_key_hex;
   guint8 *kB;
   guint8 *aes_key;
   guint8 *hmac_key;
-  guint8 *default_aes_key;
-  guint8 *default_hmac_key;
-  gsize len;
 
   service = ephy_shell_get_sync_service (ephy_shell_get_default ());
 
@@ -953,30 +940,33 @@ obtain_default_sync_keys_cb (SoupSession *session,
   /* Under no circumstances should a client try to decrypt a record if the HMAC
    * verification fails. If the verification is successful, proceed to decrypt
    * the record and retrieve the default sync keys. Otherwise, signal the error
-   * to the user.*/
+   * to the user. */
   if (!ephy_sync_crypto_sha256_hmac_is_valid (ciphertext_b64, hmac_key, hmac)) {
     g_warning ("Failed to verify the HMAC value of the crypto/keys record");
   } else {
     record = ephy_sync_crypto_decrypt_record (ciphertext_b64, iv_b64, aes_key);
     json_parser_load_from_data (parser, record, -1, NULL);
     json = json_node_get_object (json_parser_get_root (parser));
-    array = json_object_get_array_member (json, "default");
 
-    /* TODO: Handle the case when the decrypted record has a non-empty "collections" member.
-     * https://github.com/michielbdejong/fxsync-webcrypto/issues/19 */
-
-    default_aes_key = g_base64_decode (json_array_get_string_element (array, 0), &len);
-    default_hmac_key = g_base64_decode (json_array_get_string_element (array, 1), &len);
-    default_aes_key_hex = ephy_sync_crypto_encode_hex (default_aes_key, 0);
-    default_hmac_key_hex = ephy_sync_crypto_encode_hex (default_hmac_key, 0);
-    ephy_sync_service_set_token (service, default_aes_key_hex, TOKEN_DEFAULT_AES_KEY);
-    ephy_sync_service_set_token (service, default_hmac_key_hex, TOKEN_DEFAULT_HMAC_KEY);
+    /* Get the default key bundle. This is always present. */
+    array = json_object_get_array_member (json, "default");
+    g_hash_table_insert (service->key_bundles,
+                         (char *)"default",
+                         ephy_sync_crypto_key_bundle_from_array (array));
+
+    /* Get the per-collection key bundles, if any. */
+    collections = json_object_get_object_member (json, "collections");
+    json_object_iter_init (&iter, collections);
+    while (json_object_iter_next (&iter, &member, &node)) {
+      if (JSON_NODE_HOLDS_ARRAY (node)) {
+        array = json_node_get_array (node);
+        g_hash_table_insert (service->key_bundles,
+                             (char *)member,
+                             ephy_sync_crypto_key_bundle_from_array (array));
+      }
+    }
 
     g_free (record);
-    g_free (default_aes_key);
-    g_free (default_hmac_key);
-    g_free (default_aes_key_hex);
-    g_free (default_hmac_key_hex);
   }
 
   g_free (payload);
@@ -990,13 +980,14 @@ out:
 }
 
 static void
-ephy_sync_service_obtain_default_sync_keys (EphySyncService *self)
+ephy_sync_service_obtain_sync_key_bundles (EphySyncService *self)
 {
   g_assert (EPHY_IS_SYNC_SERVICE (self));
 
+  g_hash_table_remove_all (self->key_bundles);
   ephy_sync_service_queue_storage_request (self, "storage/crypto/keys",
                                            SOUP_METHOD_GET, NULL, -1, -1,
-                                           obtain_default_sync_keys_cb, NULL);
+                                           obtain_sync_key_bundles, NULL);
 }
 
 static void
diff --git a/src/sync/ephy-sync-utils.c b/src/sync/ephy-sync-utils.c
index ca60d5f..73b17d4 100644
--- a/src/sync/ephy-sync-utils.c
+++ b/src/sync/ephy-sync-utils.c
@@ -101,10 +101,6 @@ ephy_sync_utils_token_name_from_type (EphySyncTokenType type)
       return "sessionToken";
     case TOKEN_KB:
       return "kB";
-    case TOKEN_DEFAULT_AES_KEY:
-      return "defaultAESKey";
-    case TOKEN_DEFAULT_HMAC_KEY:
-      return "defaultHMACKey";
     default:
       g_assert_not_reached ();
   }
@@ -119,10 +115,6 @@ ephy_sync_utils_token_type_from_name (const char *name)
     return TOKEN_SESSIONTOKEN;
   } else if (!g_strcmp0 (name, "kB")) {
     return TOKEN_KB;
-  } else if (!g_strcmp0 (name, "defaultAESKey")) {
-    return TOKEN_DEFAULT_AES_KEY;
-  } else if (!g_strcmp0 (name, "defaultHMACKey")) {
-    return TOKEN_DEFAULT_HMAC_KEY;
   } else {
     g_assert_not_reached ();
   }
diff --git a/src/sync/ephy-sync-utils.h b/src/sync/ephy-sync-utils.h
index 4da216b..10340a8 100644
--- a/src/sync/ephy-sync-utils.h
+++ b/src/sync/ephy-sync-utils.h
@@ -25,9 +25,7 @@
 typedef enum {
   TOKEN_UID,
   TOKEN_SESSIONTOKEN,
-  TOKEN_KB,
-  TOKEN_DEFAULT_AES_KEY,
-  TOKEN_DEFAULT_HMAC_KEY
+  TOKEN_KB
 } EphySyncTokenType;
 
 G_BEGIN_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]