summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Ivascu <ivascu.gabriel59@gmail.com>2017-06-12 18:05:49 +0300
committerMichael Catanzaro <mcatanzaro@igalia.com>2017-08-06 09:28:09 -0500
commitc4c0acd128807c53bbf034be065bc22e98223d27 (patch)
treeb5678b82f2a1d168a6fed510525de7d45a8768b4
parentff16aaff81495e7b0eca03fb358236f68bd7bb96 (diff)
downloadepiphany-c4c0acd128807c53bbf034be065bc22e98223d27.tar.gz
sync: Rename and reorder some functions
-rw-r--r--lib/sync/README15
-rw-r--r--lib/sync/debug/ephy-sync-debug.c33
-rw-r--r--lib/sync/ephy-sync-crypto.c1307
-rw-r--r--lib/sync/ephy-sync-crypto.h102
-rw-r--r--lib/sync/ephy-sync-service.c450
-rw-r--r--lib/sync/ephy-sync-service.h32
-rw-r--r--src/prefs-dialog.c16
7 files changed, 967 insertions, 988 deletions
diff --git a/lib/sync/README b/lib/sync/README
index 08117fdc1..95f73537d 100644
--- a/lib/sync/README
+++ b/lib/sync/README
@@ -393,16 +393,17 @@
EphySyncCrypto is a helper module that handles all the cryptographic stuff.
Its API include:
- * _process_session_token(). Derives the Hawk id and key from a sessionToken.
+ * _derive_session_token(). Derives the Hawk id and key from a sessionToken.
- * _process_key_fetch_token(). Derives the Hawk id and key, the response HMAC
+ * _derive_key_fetch_token(). Derives the Hawk id and key, the response HMAC
key and the response XOR key from a keyFetchToken.
- * _compute_sync_keys(). Derives the Master Sync Key from the unwrapBKey
+ * _derive_master_keys(). Derives the Master Sync Key from the unwrapBKey
token, the bundle returned by the /accounts/keys endpoint of the Firefox
- Accounts Server, the response HMAC key and the response XOR key.
+ Accounts Server, the response HMAC key and the response XOR key. kB is
+ the Master Sync Key and kA is left unused.
- * _derive_key_bundle(). Derives the key bundle from the Master Sync Key.
+ * _derive_master_bundle(). Derives the key bundle from the Master Sync Key.
* _generate_crypto_keys(). Generates a new crypto/keys record.
@@ -410,13 +411,13 @@
* _decrypt_record(). Decrypts a BSO payload into a clear text.
- * _generate_rsa_key_pair(). Generates a RSA key pair. This is needed when
+ * _rsa_key_pair_new(). Generates a RSA key pair. This is needed when
obtaining an identify certificate and creating the BrowserID assertion.
* _create_assertion(). Creates a BrowserID assertion from a certificate, an
audience and a RSA key pair.
- * _compute_hawk_header(). Creates a Hawk header that is used to authorize
+ * _hawk_header_new(). Creates a Hawk header that is used to authorize
Hawk requests. Unfortunately, there isn't any C library for creating Hawk
headers so the code has been reproduced from a Python library [19].
diff --git a/lib/sync/debug/ephy-sync-debug.c b/lib/sync/debug/ephy-sync-debug.c
index 314ee1852..3cf7f16c2 100644
--- a/lib/sync/debug/ephy-sync-debug.c
+++ b/lib/sync/debug/ephy-sync-debug.c
@@ -114,7 +114,7 @@ ephy_sync_debug_get_bundle_for_collection (const char *collection)
array = json_object_has_member (collections, collection) ?
json_object_get_array_member (collections, collection) :
json_object_get_array_member (json, "default");
- bundle = ephy_sync_crypto_key_bundle_from_array (array);
+ bundle = ephy_sync_crypto_key_bundle_new (array);
json_node_unref (node);
free_secrets:
@@ -216,9 +216,8 @@ ephy_sync_debug_prepare_soup_message (const char *url,
if (!g_strcmp0 (method, "PUT") || !g_strcmp0(method, "POST"))
soup_message_headers_append (msg->request_headers, "content-type", content_type);
- header = ephy_sync_crypto_compute_hawk_header (url, method, hawk_id,
- hawk_key, hawk_key_len,
- options);
+ header = ephy_sync_crypto_hawk_header_new (url, method, hawk_id,
+ hawk_key, hawk_key_len, options);
soup_message_headers_append (msg->request_headers, "authorization", header->header);
ephy_sync_crypto_hawk_header_free (header);
@@ -254,7 +253,7 @@ ephy_sync_debug_get_signed_certificate (const char *session_token,
g_assert (session_token);
g_assert (keypair);
- ephy_sync_crypto_process_session_token (session_token, &id, &key, &tmp, 32);
+ ephy_sync_crypto_derive_session_token (session_token, &id, &key, &tmp);
id_hex = ephy_sync_utils_encode_hex (id, 32);
n = mpz_get_str (NULL, 10, keypair->public.n);
e = mpz_get_str (NULL, 10, keypair->public.e);
@@ -324,10 +323,10 @@ ephy_sync_debug_get_storage_credentials (char **storage_endpoint,
char *certificate;
char *audience;
char *assertion;
- char *hashed_key_b;
+ char *hashed_kb;
char *client_state;
char *authorization;
- guint8 *key_b;
+ guint8 *kb;
const char *session_token;
guint status_code;
gboolean success = FALSE;
@@ -336,7 +335,7 @@ ephy_sync_debug_get_storage_credentials (char **storage_endpoint,
if (!secrets)
return FALSE;
- keypair = ephy_sync_crypto_generate_rsa_key_pair ();
+ keypair = ephy_sync_crypto_rsa_key_pair_new ();
session_token = json_object_get_string_member (secrets, "session_token");
certificate = ephy_sync_debug_get_signed_certificate (session_token, keypair);
if (!certificate)
@@ -344,9 +343,9 @@ ephy_sync_debug_get_storage_credentials (char **storage_endpoint,
audience = ephy_sync_utils_get_audience (TOKEN_SERVER_URL);
assertion = ephy_sync_crypto_create_assertion (certificate, audience, 300, keypair);
- key_b = ephy_sync_utils_decode_hex (json_object_get_string_member (secrets, "master_key"));
- hashed_key_b = g_compute_checksum_for_data (G_CHECKSUM_SHA256, key_b, 32);
- client_state = g_strndup (hashed_key_b, 32);
+ kb = ephy_sync_utils_decode_hex (json_object_get_string_member (secrets, "master_key"));
+ hashed_kb = g_compute_checksum_for_data (G_CHECKSUM_SHA256, kb, 32);
+ client_state = g_strndup (hashed_kb, 32);
authorization = g_strdup_printf ("BrowserID %s", assertion);
msg = soup_message_new ("GET", TOKEN_SERVER_URL);
soup_message_headers_append (msg->request_headers, "X-Client-State", client_state);
@@ -378,8 +377,8 @@ free_session:
g_object_unref (msg);
g_free (authorization);
g_free (client_state);
- g_free (hashed_key_b);
- g_free (key_b);
+ g_free (hashed_kb);
+ g_free (kb);
g_free (assertion);
g_free (audience);
g_free (certificate);
@@ -895,7 +894,7 @@ ephy_sync_debug_view_crypto_keys_record (void)
char *crypto_keys;
const char *payload;
const char *key_b_hex;
- guint8 *key_b;
+ guint8 *kb;
secrets = ephy_sync_debug_load_secrets ();
if (!secrets)
@@ -915,8 +914,8 @@ ephy_sync_debug_view_crypto_keys_record (void)
json = json_node_get_object (node);
payload = json_object_get_string_member (json, "payload");
key_b_hex = json_object_get_string_member (secrets, "master_key");
- key_b = ephy_sync_utils_decode_hex (key_b_hex);
- bundle = ephy_sync_crypto_derive_key_bundle (key_b, 32);
+ kb = ephy_sync_utils_decode_hex (key_b_hex);
+ bundle = ephy_sync_crypto_derive_master_bundle (kb);
crypto_keys = ephy_sync_crypto_decrypt_record (payload, bundle);
if (!crypto_keys)
@@ -927,7 +926,7 @@ ephy_sync_debug_view_crypto_keys_record (void)
g_free (crypto_keys);
free_bundle:
ephy_sync_crypto_key_bundle_free (bundle);
- g_free (key_b);
+ g_free (kb);
json_node_unref (node);
free_response:
g_free (response);
diff --git a/lib/sync/ephy-sync-crypto.c b/lib/sync/ephy-sync-crypto.c
index d7b6a33c5..e18784c5f 100644
--- a/lib/sync/ephy-sync-crypto.c
+++ b/lib/sync/ephy-sync-crypto.c
@@ -127,148 +127,6 @@ ephy_sync_crypto_hawk_artifacts_free (SyncCryptoHawkArtifacts *artifacts)
g_slice_free (SyncCryptoHawkArtifacts, artifacts);
}
-static SyncCryptoHawkHeader *
-ephy_sync_crypto_hawk_header_new (const char *header,
- SyncCryptoHawkArtifacts *artifacts)
-{
- SyncCryptoHawkHeader *hawk_header;
-
- hawk_header = g_slice_new (SyncCryptoHawkHeader);
- hawk_header->header = g_strdup (header);
- hawk_header->artifacts = artifacts;
-
- return hawk_header;
-}
-
-void
-ephy_sync_crypto_hawk_header_free (SyncCryptoHawkHeader *hawk_header)
-{
- g_return_if_fail (hawk_header);
-
- g_free (hawk_header->header);
- ephy_sync_crypto_hawk_artifacts_free (hawk_header->artifacts);
-
- g_slice_free (SyncCryptoHawkHeader, hawk_header);
-}
-
-static SyncCryptoRSAKeyPair *
-ephy_sync_crypto_rsa_key_pair_new (struct rsa_public_key public,
- struct rsa_private_key private)
-{
- SyncCryptoRSAKeyPair *rsa_key_pair;
-
- rsa_key_pair = g_slice_new (SyncCryptoRSAKeyPair);
- rsa_key_pair->public = public;
- rsa_key_pair->private = private;
-
- return rsa_key_pair;
-}
-
-void
-ephy_sync_crypto_rsa_key_pair_free (SyncCryptoRSAKeyPair *rsa_key_pair)
-{
- g_return_if_fail (rsa_key_pair);
-
- rsa_public_key_clear (&rsa_key_pair->public);
- rsa_private_key_clear (&rsa_key_pair->private);
-
- g_slice_free (SyncCryptoRSAKeyPair, rsa_key_pair);
-}
-
-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_utils_encode_hex (aes_key, 32);
- hmac_key_hex = ephy_sync_utils_encode_hex (hmac_key, 32);
- 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)
-{
- g_assert (name);
-
- /* Concatenate the given name to the Mozilla prefix.
- * See https://raw.githubusercontent.com/wiki/mozilla/fxa-auth-server/images/onepw-create.png
- */
- return g_strconcat ("identity.mozilla.com/picl/v1/", name, NULL);
-}
-
-static guint8 *
-ephy_sync_crypto_xor (const guint8 *a,
- const guint8 *b,
- gsize length)
-{
- guint8 *xored;
-
- g_assert (a);
- g_assert (b);
-
- xored = g_malloc (length);
- for (gsize i = 0; i < length; i++)
- xored[i] = a[i] ^ b[i];
-
- return xored;
-}
-
-static gboolean
-ephy_sync_crypto_equals (const guint8 *a,
- const guint8 *b,
- gsize length)
-{
- g_assert (a);
- g_assert (b);
-
- for (gsize i = 0; i < length; i++)
- if (a[i] != b[i])
- return FALSE;
-
- return TRUE;
-}
-
static char *
ephy_sync_crypto_find_and_replace (const char *where,
const char *to_find,
@@ -307,8 +165,71 @@ ephy_sync_crypto_find_and_replace (const char *where,
}
static char *
-ephy_sync_crypto_normalize_string (const char *type,
- SyncCryptoHawkArtifacts *artifacts)
+hawk_parse_content_type (const char *content_type)
+{
+ char **tokens;
+ char *retval;
+
+ g_assert (content_type);
+
+ tokens = g_strsplit (content_type, ";", -1);
+ retval = g_ascii_strdown (g_strstrip (tokens[0]), -1);
+ g_strfreev (tokens);
+
+ return retval;
+}
+
+static char *
+hawk_compute_payload_hash (const char *payload,
+ const char *content_type)
+{
+ guint8 *digest;
+ char *digest_hex;
+ char *content;
+ char *update;
+ char *hash;
+
+ g_assert (payload);
+ g_assert (content_type);
+
+ content = hawk_parse_content_type (content_type);
+ update = g_strdup_printf ("hawk.%d.payload\n%s\n%s\n",
+ HAWK_VERSION, content, payload);
+
+ digest_hex = g_compute_checksum_for_string (G_CHECKSUM_SHA256, update, -1);
+ digest = ephy_sync_utils_decode_hex (digest_hex);
+ hash = g_base64_encode (digest, g_checksum_type_get_length (G_CHECKSUM_SHA256));
+
+ g_free (content);
+ g_free (update);
+ g_free (digest_hex);
+ g_free (digest);
+
+ return hash;
+}
+
+static char *
+hawk_append_to_header (char *header,
+ const char *name,
+ const char *value)
+{
+ char *new_header;
+ char *tmp;
+
+ g_assert (header);
+ g_assert (name);
+ g_assert (value);
+
+ tmp = header;
+ new_header = g_strconcat (header, ", ", name, "=\"", value, "\"", NULL);
+ g_free (tmp);
+
+ return new_header;
+}
+
+static char *
+hawk_normalize_string (const char *type,
+ SyncCryptoHawkArtifacts *artifacts)
{
char *host;
char *info;
@@ -355,54 +276,10 @@ ephy_sync_crypto_normalize_string (const char *type,
}
static char *
-ephy_sync_crypto_parse_content_type (const char *content_type)
-{
- char **tokens;
- char *retval;
-
- g_assert (content_type);
-
- tokens = g_strsplit (content_type, ";", -1);
- retval = g_ascii_strdown (g_strstrip (tokens[0]), -1);
- g_strfreev (tokens);
-
- return retval;
-}
-
-static char *
-ephy_sync_crypto_calculate_payload_hash (const char *payload,
- const char *content_type)
-{
- guint8 *digest;
- char *digest_hex;
- char *content;
- char *update;
- char *hash;
-
- g_assert (payload);
- g_assert (content_type);
-
- content = ephy_sync_crypto_parse_content_type (content_type);
- update = g_strdup_printf ("hawk.%d.payload\n%s\n%s\n",
- HAWK_VERSION, content, payload);
-
- digest_hex = g_compute_checksum_for_string (G_CHECKSUM_SHA256, update, -1);
- digest = ephy_sync_utils_decode_hex (digest_hex);
- hash = g_base64_encode (digest, g_checksum_type_get_length (G_CHECKSUM_SHA256));
-
- g_free (content);
- g_free (update);
- g_free (digest_hex);
- g_free (digest);
-
- return hash;
-}
-
-static char *
-ephy_sync_crypto_calculate_mac (const char *type,
- const guint8 *key,
- gsize key_len,
- SyncCryptoHawkArtifacts *artifacts)
+hawk_compute_mac (const char *type,
+ const guint8 *key,
+ gsize key_len,
+ SyncCryptoHawkArtifacts *artifacts)
{
guint8 *digest;
char *digest_hex;
@@ -414,7 +291,7 @@ ephy_sync_crypto_calculate_mac (const char *type,
g_assert (artifacts);
/* Serialize the mac type and artifacts into a HAWK string. */
- normalized = ephy_sync_crypto_normalize_string (type, artifacts);
+ normalized = hawk_normalize_string (type, artifacts);
digest_hex = g_compute_hmac_for_string (G_CHECKSUM_SHA256,
key, key_len,
normalized, -1);
@@ -428,28 +305,234 @@ ephy_sync_crypto_calculate_mac (const char *type,
return mac;
}
-static char *
-ephy_sync_crypto_append_to_header (char *header,
- const char *name,
- const char *value)
+SyncCryptoHawkHeader *
+ephy_sync_crypto_hawk_header_new (const char *url,
+ const char *method,
+ const char *id,
+ const guint8 *key,
+ gsize key_len,
+ SyncCryptoHawkOptions *options)
{
- char *new_header;
- char *tmp;
+ SyncCryptoHawkHeader *hawk_header;
+ SyncCryptoHawkArtifacts *artifacts;
+ SoupURI *uri;
+ char *resource;
+ char *hash;
+ char *header;
+ char *mac;
+ char *nonce;
+ char *payload;
+ char *timestamp;
+ guint8 *bytes;
+ gint64 ts;
- g_assert (header);
- g_assert (name);
- g_assert (value);
+ g_return_val_if_fail (url, NULL);
+ g_return_val_if_fail (method, NULL);
+ g_return_val_if_fail (id, NULL);
+ g_return_val_if_fail (key, NULL);
- tmp = header;
- new_header = g_strconcat (header, ", ", name, "=\"", value, "\"", NULL);
- g_free (tmp);
+ ts = g_get_real_time () / 1000000;
+ hash = options ? g_strdup (options->hash) : NULL;
+ payload = options ? options->payload : NULL;
+ timestamp = options ? options->timestamp : NULL;
+ uri = soup_uri_new (url);
+ resource = !soup_uri_get_query (uri) ? g_strdup (soup_uri_get_path (uri))
+ : g_strconcat (soup_uri_get_path (uri),
+ "?",
+ soup_uri_get_query (uri),
+ NULL);
- return new_header;
+ if (options && options->nonce) {
+ nonce = g_strdup (options->nonce);
+ } else {
+ bytes = g_malloc (NONCE_LEN / 2);
+ ephy_sync_utils_generate_random_bytes (NULL, NONCE_LEN / 2, bytes);
+ nonce = ephy_sync_utils_encode_hex (bytes, NONCE_LEN / 2);
+ g_free (bytes);
+ }
+
+ if (timestamp) {
+ char *local_time_offset;
+ gint64 offset;
+
+ local_time_offset = options ? options->local_time_offset : NULL;
+ offset = local_time_offset ? g_ascii_strtoll (local_time_offset, NULL, 10) : 0;
+ ts = g_ascii_strtoll (timestamp, NULL, 10) + offset;
+ }
+
+ if (!hash && payload) {
+ const char *content_type = options ? options->content_type : "text/plain";
+
+ /* Calculate hash for the given payload. */
+ hash = hawk_compute_payload_hash (payload, content_type);
+ }
+
+ /* Create artifacts from options. */
+ artifacts = ephy_sync_crypto_hawk_artifacts_new (options ? options->app : NULL,
+ options ? options->dlg : NULL,
+ options ? options->ext : NULL,
+ hash,
+ soup_uri_get_host (uri),
+ method,
+ nonce,
+ soup_uri_get_port (uri),
+ resource,
+ ts);
+
+ header = g_strconcat ("Hawk id=\"", id, "\"",
+ ", ts=\"", artifacts->ts, "\"",
+ ", nonce=\"", artifacts->nonce, "\"",
+ NULL);
+
+ /* Append pre-calculated payload hash if any. */
+ if (artifacts->hash && strlen (artifacts->hash) > 0)
+ header = hawk_append_to_header (header, "hash", artifacts->hash);
+
+ /* Append the application specific data if any. */
+ if (artifacts->ext && strlen (artifacts->ext) > 0) {
+ char *h_ext;
+ char *tmp_ext;
+
+ tmp_ext = ephy_sync_crypto_find_and_replace (artifacts->ext, "\\", "\\\\");
+ h_ext = ephy_sync_crypto_find_and_replace (tmp_ext, "\n", "\\n");
+ header = hawk_append_to_header (header, "ext", h_ext);
+
+ g_free (h_ext);
+ g_free (tmp_ext);
+ }
+
+ /* Calculate and append a message authentication code (MAC). */
+ mac = hawk_compute_mac ("header", key, key_len, artifacts);
+ header = hawk_append_to_header (header, "mac", mac);
+
+ /* Append the Oz application id if any. */
+ if (artifacts->app) {
+ header = hawk_append_to_header (header, "app", artifacts->app);
+
+ /* Append the Oz delegated-by application id if any. */
+ if (artifacts->dlg)
+ header = hawk_append_to_header (header, "dlg", artifacts->dlg);
+ }
+
+ hawk_header = g_slice_new (SyncCryptoHawkHeader);
+ hawk_header->header = g_strdup (header);
+ hawk_header->artifacts = artifacts;
+
+ soup_uri_free (uri);
+ g_free (hash);
+ g_free (mac);
+ g_free (nonce);
+ g_free (resource);
+ g_free (header);
+
+ return hawk_header;
+}
+
+void
+ephy_sync_crypto_hawk_header_free (SyncCryptoHawkHeader *header)
+{
+ g_return_if_fail (header);
+
+ g_free (header->header);
+ ephy_sync_crypto_hawk_artifacts_free (header->artifacts);
+
+ g_slice_free (SyncCryptoHawkHeader, header);
+}
+
+SyncCryptoRSAKeyPair *
+ephy_sync_crypto_rsa_key_pair_new (void)
+{
+ SyncCryptoRSAKeyPair *key_pair;
+ struct rsa_public_key public;
+ struct rsa_private_key private;
+ int success;
+
+ rsa_public_key_init (&public);
+ rsa_private_key_init (&private);
+
+ /* The public exponent, usually one of the small Fermat primes 3, 5, 17, 257, 65537. */
+ mpz_set_ui (public.e, 65537);
+
+ /* Key sizes below 2048 are considered breakable and should not be used. */
+ success = rsa_generate_keypair (&public, &private,
+ NULL, ephy_sync_utils_generate_random_bytes,
+ NULL, NULL, 2048, 0);
+ /* Given correct parameters, this never fails. */
+ g_assert (success);
+
+ key_pair = g_slice_new (SyncCryptoRSAKeyPair);
+ key_pair->public = public;
+ key_pair->private = private;
+
+ return key_pair;
+}
+
+void
+ephy_sync_crypto_rsa_key_pair_free (SyncCryptoRSAKeyPair *key_pair)
+{
+ g_return_if_fail (key_pair);
+
+ rsa_public_key_clear (&key_pair->public);
+ rsa_private_key_clear (&key_pair->private);
+
+ g_slice_free (SyncCryptoRSAKeyPair, key_pair);
+}
+
+SyncCryptoKeyBundle *
+ephy_sync_crypto_key_bundle_new (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_utils_encode_hex (aes_key, 32);
+ hmac_key_hex = ephy_sync_utils_encode_hex (hmac_key, 32);
+
+ bundle = g_slice_new (SyncCryptoKeyBundle);
+ bundle->aes_key_hex = g_strdup (aes_key_hex);
+ bundle->hmac_key_hex = g_strdup (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)
+{
+ g_assert (name);
+
+ /* Concatenate the given name to the Mozilla prefix.
+ * See https://raw.githubusercontent.com/wiki/mozilla/fxa-auth-server/images/onepw-create.png
+ */
+ return g_strconcat ("identity.mozilla.com/picl/v1/", name, NULL);
}
static guint8 *
ephy_sync_crypto_concat_bytes (const guint8 *bytes,
- gsize bytes_len,
+ gsize len,
...)
{
va_list args;
@@ -458,11 +541,11 @@ ephy_sync_crypto_concat_bytes (const guint8 *bytes,
gsize next_len;
gsize out_len;
- out_len = bytes_len;
+ out_len = len;
out = g_malloc (out_len);
memcpy (out, bytes, out_len);
- va_start (args, bytes_len);
+ va_start (args, len);
while ((next = va_arg (args, guint8 *)) != NULL) {
next_len = va_arg (args, gsize);
out = g_realloc (out, out_len + next_len);
@@ -504,7 +587,8 @@ ephy_sync_crypto_hkdf (const guint8 *in,
g_assert (out_len <= hash_len * 255);
/* Implementation of the HMAC-based Extract-and-Expand Key Derivation Function.
- * See https://tools.ietf.org/html/rfc5869 */
+ * See https://tools.ietf.org/html/rfc5869
+ */
/* If salt value was not provided, use an array of hash_len zeros. */
if (!salt) {
@@ -554,136 +638,50 @@ ephy_sync_crypto_hkdf (const guint8 *in,
g_free (out_full);
}
-static guint8 *
-ephy_sync_crypto_pad (const char *text,
- gsize block_len,
- gsize *out_len)
+void
+ephy_sync_crypto_derive_session_token (const char *session_token,
+ guint8 **token_id,
+ guint8 **req_hmac_key,
+ guint8 **request_key)
{
+ guint8 *token;
guint8 *out;
- gsize text_len = strlen (text);
-
- g_assert (text);
- g_assert (out_len);
-
- if (text_len % block_len == 0)
- *out_len = text_len;
- else
- *out_len = text_len + block_len - text_len % block_len;
-
- out = g_malloc (*out_len);
-
- if (text_len % block_len != 0)
- memset (out, block_len - text_len % block_len, *out_len);
-
- memcpy (out, text, text_len);
-
- return out;
-}
-
-static guint8 *
-ephy_sync_crypto_aes_256_encrypt (const char *text,
- const guint8 *key,
- const guint8 *iv,
- gsize *out_len)
-{
- guint8 *padded;
- guint8 *encrypted;
- gsize padded_len;
- struct CBC_CTX(struct aes256_ctx, AES_BLOCK_SIZE) ctx;
-
- g_assert (text);
- g_assert (key);
- g_assert (iv);
- g_assert (out_len);
-
- padded = ephy_sync_crypto_pad (text, AES_BLOCK_SIZE, &padded_len);
- encrypted = g_malloc (padded_len);
-
- aes256_set_encrypt_key(&ctx.ctx, key);
- CBC_SET_IV(&ctx, iv);
- CBC_ENCRYPT(&ctx, aes256_encrypt, padded_len, encrypted, padded);
-
- *out_len = padded_len;
- g_free (padded);
-
- return encrypted;
-}
-
-static char *
-ephy_sync_crypto_unpad (const guint8 *data,
- gsize data_len,
- gsize block_len)
-{
- char *out;
- gsize out_len;
- gsize padding = data[data_len - 1];
-
- g_assert (data);
-
- if (padding >= 1 && padding <= block_len)
- out_len = data_len - padding;
- else
- out_len = data_len;
-
- out = g_malloc0 (out_len + 1);
- memcpy (out, data, out_len);
-
- return out;
-}
-
-static char *
-ephy_sync_crypto_aes_256_decrypt (const guint8 *data,
- gsize data_len,
- const guint8 *key,
- const guint8 *iv)
-{
- guint8 *decrypted;
- char *unpadded;
- struct CBC_CTX(struct aes256_ctx, AES_BLOCK_SIZE) ctx;
-
- g_assert (data);
- g_assert (key);
- g_assert (iv);
-
- decrypted = g_malloc (data_len);
-
- aes256_set_decrypt_key (&ctx.ctx, key);
- CBC_SET_IV (&ctx, iv);
- CBC_DECRYPT (&ctx, aes256_decrypt, data_len, decrypted, data);
-
- unpadded = ephy_sync_crypto_unpad (decrypted, data_len, AES_BLOCK_SIZE);
- g_free (decrypted);
+ char *info;
+ gsize len = 32; /* sessionToken is always 32 bytes. */
- return unpadded;
-}
+ g_return_if_fail (session_token);
+ g_return_if_fail (token_id);
+ g_return_if_fail (req_hmac_key);
+ g_return_if_fail (request_key);
-static gboolean
-ephy_sync_crypto_hmac_is_valid (const char *text,
- const guint8 *key,
- const char *expected)
-{
- char *hmac;
- gboolean retval;
+ token = ephy_sync_utils_decode_hex (session_token);
+ info = ephy_sync_crypto_kw ("sessionToken");
+ out = g_malloc (3 * len);
- g_assert (text);
- g_assert (key);
- g_assert (expected);
+ /* Use the sessionToken to derive tokenID, reqHMACkey and requestKey. */
+ ephy_sync_crypto_hkdf (token, len,
+ NULL, 0,
+ (guint8 *)info, strlen (info),
+ out, 3 * len);
- /* SHA256 expects a 32 bytes key. */
- hmac = g_compute_hmac_for_string (G_CHECKSUM_SHA256, key, 32, text, -1);
- retval = g_strcmp0 (hmac, expected) == 0;
- g_free (hmac);
+ *token_id = g_malloc (len);
+ *req_hmac_key = g_malloc (len);
+ *request_key = g_malloc (len);
+ memcpy (*token_id, out, len);
+ memcpy (*req_hmac_key, out + len, len);
+ memcpy (*request_key, out + 2 * len, len);
- return retval;
+ g_free (token);
+ g_free (out);
+ g_free (info);
}
void
-ephy_sync_crypto_process_key_fetch_token (const char *key_fetch_token,
- guint8 **token_id,
- guint8 **req_hmac_key,
- guint8 **resp_hmac_key,
- guint8 **resp_xor_key,
- gsize token_len)
+ephy_sync_crypto_derive_key_fetch_token (const char *key_fetch_token,
+ guint8 **token_id,
+ guint8 **req_hmac_key,
+ guint8 **resp_hmac_key,
+ guint8 **resp_xor_key)
{
guint8 *kft;
guint8 *out1;
@@ -691,6 +689,7 @@ ephy_sync_crypto_process_key_fetch_token (const char *key_fetch_token,
guint8 *key_request_key;
char *info_kft;
char *info_keys;
+ gsize len = 32; /* keyFetchToken is always 32 bytes. */
g_return_if_fail (key_fetch_token);
g_return_if_fail (token_id);
@@ -701,32 +700,32 @@ ephy_sync_crypto_process_key_fetch_token (const char *key_fetch_token,
kft = ephy_sync_utils_decode_hex (key_fetch_token);
info_kft = ephy_sync_crypto_kw ("keyFetchToken");
info_keys = ephy_sync_crypto_kw ("account/keys");
- out1 = g_malloc (3 * token_len);
- out2 = g_malloc (3 * token_len);
+ out1 = g_malloc (3 * len);
+ out2 = g_malloc (3 * len);
/* Use the keyFetchToken to derive tokenID, reqHMACkey and keyRequestKey. */
- ephy_sync_crypto_hkdf (kft, token_len,
+ ephy_sync_crypto_hkdf (kft, len,
NULL, 0,
(guint8 *)info_kft, strlen (info_kft),
- out1, 3 * token_len);
+ out1, 3 * len);
- *token_id = g_malloc (token_len);
- *req_hmac_key = g_malloc (token_len);
- key_request_key = g_malloc (token_len);
- memcpy (*token_id, out1, token_len);
- memcpy (*req_hmac_key, out1 + token_len, token_len);
- memcpy (key_request_key, out1 + 2 * token_len, token_len);
+ *token_id = g_malloc (len);
+ *req_hmac_key = g_malloc (len);
+ key_request_key = g_malloc (len);
+ memcpy (*token_id, out1, len);
+ memcpy (*req_hmac_key, out1 + len, len);
+ memcpy (key_request_key, out1 + 2 * len, len);
/* Use the keyRequestKey to derive respHMACkey and respXORkey. */
- ephy_sync_crypto_hkdf (key_request_key, token_len,
+ ephy_sync_crypto_hkdf (key_request_key, len,
NULL, 0,
(guint8 *)info_keys, strlen (info_keys),
- out2, 3 * token_len);
+ out2, 3 * len);
- *resp_hmac_key = g_malloc (token_len);
- *resp_xor_key = g_malloc (2 * token_len);
- memcpy (*resp_hmac_key, out2, token_len);
- memcpy (*resp_xor_key, out2 + token_len, 2 * token_len);
+ *resp_hmac_key = g_malloc (len);
+ *resp_xor_key = g_malloc (2 * len);
+ memcpy (*resp_hmac_key, out2, len);
+ memcpy (*resp_xor_key, out2 + len, 2 * len);
g_free (kft);
g_free (out1);
@@ -736,97 +735,92 @@ ephy_sync_crypto_process_key_fetch_token (const char *key_fetch_token,
g_free (key_request_key);
}
-void
-ephy_sync_crypto_process_session_token (const char *session_token,
- guint8 **token_id,
- guint8 **req_hmac_key,
- guint8 **request_key,
- gsize token_len)
+static guint8 *
+ephy_sync_crypto_xor_bytes (const guint8 *a,
+ const guint8 *b,
+ gsize len)
{
- guint8 *st;
- guint8 *out;
- char *info;
+ guint8 *xored;
- g_return_if_fail (session_token);
- g_return_if_fail (token_id);
- g_return_if_fail (req_hmac_key);
- g_return_if_fail (request_key);
+ g_assert (a);
+ g_assert (b);
- st = ephy_sync_utils_decode_hex (session_token);
- info = ephy_sync_crypto_kw ("sessionToken");
- out = g_malloc (3 * token_len);
+ xored = g_malloc (len);
+ for (gsize i = 0; i < len; i++)
+ xored[i] = a[i] ^ b[i];
- /* Use the sessionToken to derive tokenID, reqHMACkey and requestKey. */
- ephy_sync_crypto_hkdf (st, token_len,
- NULL, 0,
- (guint8 *)info, strlen (info),
- out, 3 * token_len);
+ return xored;
+}
- *token_id = g_malloc (token_len);
- *req_hmac_key = g_malloc (token_len);
- *request_key = g_malloc (token_len);
- memcpy (*token_id, out, token_len);
- memcpy (*req_hmac_key, out + token_len, token_len);
- memcpy (*request_key, out + 2 * token_len, token_len);
+static gboolean
+ephy_sync_crypto_compate_bytes (const guint8 *a,
+ const guint8 *b,
+ gsize len)
+{
+ g_assert (a);
+ g_assert (b);
- g_free (st);
- g_free (out);
- g_free (info);
+ for (gsize i = 0; i < len; i++)
+ if (a[i] != b[i])
+ return FALSE;
+
+ return TRUE;
}
gboolean
-ephy_sync_crypto_compute_sync_keys (const char *bundle_hex,
- const guint8 *resp_hmac_key,
- const guint8 *resp_xor_key,
- const guint8 *unwrap_b_key,
- guint8 **kA,
- guint8 **kB,
- gsize key_len)
+ephy_sync_crypto_derive_master_keys (const char *bundle_hex,
+ const guint8 *resp_hmac_key,
+ const guint8 *resp_xor_key,
+ const guint8 *unwrap_kb,
+ guint8 **ka,
+ guint8 **kb)
{
guint8 *bundle;
guint8 *ciphertext;
guint8 *resp_hmac;
guint8 *resp_hmac_2;
guint8 *xored;
- guint8 *wrap_key_b;
+ guint8 *wrap_kb;
char *resp_hmac_2_hex;
gboolean retval = TRUE;
+ gsize len = 32; /* The master sync keys are always 32 bytes. */
g_return_val_if_fail (bundle_hex, FALSE);
g_return_val_if_fail (resp_hmac_key, FALSE);
g_return_val_if_fail (resp_xor_key, FALSE);
- g_return_val_if_fail (unwrap_b_key, FALSE);
- g_return_val_if_fail (kA, FALSE);
- g_return_val_if_fail (kB, FALSE);
+ g_return_val_if_fail (unwrap_kb, FALSE);
+ g_return_val_if_fail (ka, FALSE);
+ g_return_val_if_fail (kb, FALSE);
bundle = ephy_sync_utils_decode_hex (bundle_hex);
- ciphertext = g_malloc (2 * key_len);
- resp_hmac = g_malloc (key_len);
+ ciphertext = g_malloc (2 * len);
+ resp_hmac = g_malloc (len);
/* Compute the MAC and compare it to the expected value. */
- memcpy (ciphertext, bundle, 2 * key_len);
- memcpy (resp_hmac, bundle + 2 * key_len, key_len);
+ memcpy (ciphertext, bundle, 2 * len);
+ memcpy (resp_hmac, bundle + 2 * len, len);
resp_hmac_2_hex = g_compute_hmac_for_data (G_CHECKSUM_SHA256,
- resp_hmac_key, key_len,
- ciphertext, 2 * key_len);
+ resp_hmac_key, len,
+ ciphertext, 2 * len);
resp_hmac_2 = ephy_sync_utils_decode_hex (resp_hmac_2_hex);
- if (!ephy_sync_crypto_equals (resp_hmac, resp_hmac_2, key_len)) {
+ if (!ephy_sync_crypto_compate_bytes (resp_hmac, resp_hmac_2, len)) {
g_warning ("HMAC values differs from the one expected");
retval = FALSE;
goto out;
}
- /* XOR the extracted ciphertext with the respXORkey, then split in into the
- * separate kA and wrap(kB) values. */
- xored = ephy_sync_crypto_xor (ciphertext, resp_xor_key, 2 * key_len);
- *kA = g_malloc (key_len);
- memcpy (*kA, xored, key_len);
- wrap_key_b = g_malloc (key_len);
- memcpy (wrap_key_b, xored + key_len, key_len);
+ /* XOR the extracted ciphertext with the respXORkey, then split into the
+ * separate kA and wrap(kB) values.
+ */
+ xored = ephy_sync_crypto_xor_bytes (ciphertext, resp_xor_key, 2 * len);
+ *ka = g_malloc (len);
+ memcpy (*ka, xored, len);
+ wrap_kb = g_malloc (len);
+ memcpy (wrap_kb, xored + len, len);
/* XOR wrap(kB) with unwrapBKey to obtain kB. There is no MAC on wrap(kB). */
- *kB = ephy_sync_crypto_xor (unwrap_b_key, wrap_key_b, key_len);
+ *kb = ephy_sync_crypto_xor_bytes (unwrap_kb, wrap_kb, len);
- g_free (wrap_key_b);
+ g_free (wrap_kb);
g_free (xored);
out:
g_free (resp_hmac_2);
@@ -839,8 +833,7 @@ out:
}
SyncCryptoKeyBundle *
-ephy_sync_crypto_derive_key_bundle (const guint8 *key,
- gsize key_len)
+ephy_sync_crypto_derive_master_bundle (const guint8 *key)
{
SyncCryptoKeyBundle *bundle;
guint8 *salt;
@@ -851,34 +844,37 @@ ephy_sync_crypto_derive_key_bundle (const guint8 *key,
char *aes_key_hex;
char *hmac_key_hex;
const char *info = "identity.mozilla.com/picl/v1/oldsync";
+ gsize len = 32; /* kB is always 32 bytes. */
g_return_val_if_fail (key, NULL);
- g_return_val_if_fail (key_len > 0, NULL);
/* Perform a two step HKDF with an all-zeros salt.
- * T(1) will represent the AES key, T(2) will represent the HMAC key. */
-
- salt = g_malloc0 (key_len);
+ * T(1) will represent the AES key, T(2) will represent the HMAC key.
+ */
+ salt = g_malloc0 (len);
prk_hex = g_compute_hmac_for_data (G_CHECKSUM_SHA256,
- salt, key_len,
- key, key_len);
+ salt, len,
+ key, len);
prk = ephy_sync_utils_decode_hex (prk_hex);
tmp = ephy_sync_crypto_concat_bytes ((guint8 *)info, strlen (info),
"\x01", 1,
NULL);
aes_key_hex = g_compute_hmac_for_data (G_CHECKSUM_SHA256,
- prk, key_len,
+ prk, len,
tmp, strlen (info) + 1);
aes_key = ephy_sync_utils_decode_hex (aes_key_hex);
g_free (tmp);
- tmp = ephy_sync_crypto_concat_bytes (aes_key, key_len,
+ tmp = ephy_sync_crypto_concat_bytes (aes_key, len,
(guint8 *)info, strlen (info),
"\x02", 1,
NULL);
hmac_key_hex = g_compute_hmac_for_data (G_CHECKSUM_SHA256,
- prk, key_len,
- tmp, key_len + strlen (info) + 1);
- bundle = ephy_sync_crypto_key_bundle_new (aes_key_hex, hmac_key_hex);
+ prk, len,
+ tmp, len + strlen (info) + 1);
+
+ bundle = g_slice_new (SyncCryptoKeyBundle);
+ bundle->aes_key_hex = g_strdup (aes_key_hex);
+ bundle->hmac_key_hex = g_strdup (hmac_key_hex);
g_free (hmac_key_hex);
g_free (tmp);
@@ -891,7 +887,7 @@ ephy_sync_crypto_derive_key_bundle (const guint8 *key,
}
char *
-ephy_sync_crypto_generate_crypto_keys (gsize key_len)
+ephy_sync_crypto_generate_crypto_keys (void)
{
JsonNode *node;
JsonObject *object;
@@ -901,13 +897,14 @@ ephy_sync_crypto_generate_crypto_keys (gsize key_len)
char *aes_key_b64;
char *hmac_key_b64;
char *payload;
+ gsize len = 32; /* Crypto keys are always 32 bytes. */
- aes_key = g_malloc (key_len);
- ephy_sync_utils_generate_random_bytes (NULL, key_len, aes_key);
- aes_key_b64 = g_base64_encode (aes_key, key_len);
- hmac_key = g_malloc (key_len);
- ephy_sync_utils_generate_random_bytes (NULL, key_len, hmac_key);
- hmac_key_b64 = g_base64_encode (hmac_key, key_len);
+ aes_key = g_malloc (len);
+ ephy_sync_utils_generate_random_bytes (NULL, len, aes_key);
+ aes_key_b64 = g_base64_encode (aes_key, len);
+ hmac_key = g_malloc (len);
+ ephy_sync_utils_generate_random_bytes (NULL, len, hmac_key);
+ hmac_key_b64 = g_base64_encode (hmac_key, len);
node = json_node_new (JSON_NODE_OBJECT);
object = json_object_new ();
@@ -932,73 +929,126 @@ ephy_sync_crypto_generate_crypto_keys (gsize key_len)
}
char *
-ephy_sync_crypto_decrypt_record (const char *payload,
- SyncCryptoKeyBundle *bundle)
+ephy_sync_crypto_create_assertion (const char *certificate,
+ const char *audience,
+ guint64 seconds,
+ SyncCryptoRSAKeyPair *key_pair)
{
- JsonNode *node = NULL;
- JsonObject *json = NULL;
- GError *error = NULL;
- guint8 *aes_key = NULL;
- guint8 *hmac_key = NULL;
- guint8 *ciphertext = NULL;
- guint8 *iv = NULL;
- char *cleartext = NULL;
- const char *ciphertext_b64;
- const char *iv_b64;
- const char *hmac;
- gsize ciphertext_len;
- gsize iv_len;
+ mpz_t signature;
+ const char *header = "{\"alg\": \"RS256\"}";
+ char *body;
+ char *body_b64;
+ char *header_b64;
+ char *to_sign;
+ char *sig_b64;
+ char *assertion;
+ char *digest_hex;
+ guint8 *digest;
+ guint8 *sig;
+ guint64 expires_at;
+ gsize expected_size;
+ gsize count;
+ int success;
- g_return_val_if_fail (payload, NULL);
- g_return_val_if_fail (bundle, NULL);
+ g_return_val_if_fail (certificate, NULL);
+ g_return_val_if_fail (audience, NULL);
+ g_return_val_if_fail (key_pair, NULL);
- /* Extract ciphertext, iv and hmac from payload. */
- node = json_from_string (payload, &error);
- if (error) {
- g_warning ("Payload is not a valid JSON: %s", error->message);
- goto out;
- }
- json = json_node_get_object (node);
- if (!json) {
- g_warning ("JSON node does not hold a JSON object");
- goto out;
- }
- ciphertext_b64 = json_object_get_string_member (json, "ciphertext");
- iv_b64 = json_object_get_string_member (json, "IV");
- hmac = json_object_get_string_member (json, "hmac");
- if (!ciphertext_b64 || !iv_b64 || !hmac) {
- g_warning ("JSON object has missing or invalid members");
- goto out;
- }
+ /* Encode the header and body to base64 url safe and join them. */
+ expires_at = g_get_real_time () / 1000 + seconds * 1000;
+ body = g_strdup_printf ("{\"exp\": %lu, \"aud\": \"%s\"}", expires_at, audience);
+ body_b64 = ephy_sync_utils_base64_urlsafe_encode ((guint8 *)body, strlen (body), TRUE);
+ header_b64 = ephy_sync_utils_base64_urlsafe_encode ((guint8 *)header, strlen (header), TRUE);
+ to_sign = g_strdup_printf ("%s.%s", header_b64, body_b64);
- /* Get the encryption key and the HMAC key. */
- aes_key = ephy_sync_utils_decode_hex (bundle->aes_key_hex);
- hmac_key = ephy_sync_utils_decode_hex (bundle->hmac_key_hex);
+ /* Compute the SHA256 hash of the message to be signed. */
+ digest_hex = g_compute_checksum_for_string (G_CHECKSUM_SHA256, to_sign, -1);
+ digest = ephy_sync_utils_decode_hex (digest_hex);
- /* Under no circumstances should a client try to decrypt a record
- * if the HMAC verification fails. */
- if (!ephy_sync_crypto_hmac_is_valid (ciphertext_b64, hmac_key, hmac)) {
- g_warning ("Incorrect HMAC value");
- goto out;
- }
+ /* Use the provided key pair to RSA sign the message. */
+ mpz_init (signature);
+ success = rsa_sha256_sign_digest_tr (&key_pair->public, &key_pair->private,
+ NULL, ephy_sync_utils_generate_random_bytes,
+ digest, signature);
+ /* Given correct parameters, this never fails. */
+ g_assert (success);
- /* Finally, decrypt the record. */
- ciphertext = g_base64_decode (ciphertext_b64, &ciphertext_len);
- iv = g_base64_decode (iv_b64, &iv_len);
- cleartext = ephy_sync_crypto_aes_256_decrypt (ciphertext, ciphertext_len,
- aes_key, iv);
+ expected_size = (mpz_sizeinbase (signature, 2) + 7) / 8;
+ sig = g_malloc (expected_size);
+ mpz_export (sig, &count, 1, sizeof (guint8), 0, 0, signature);
+ /* Given correct parameters, this never fails. */
+ g_assert (count == expected_size);
-out:
- g_free (ciphertext);
- g_free (iv);
- g_free (aes_key);
- g_free (hmac_key);
- if (node)
- json_node_unref (node);
- if (error)
- g_error_free (error);
+ /* Join certificate, header, body and signed message to create the assertion. */
+ sig_b64 = ephy_sync_utils_base64_urlsafe_encode (sig, count, TRUE);
+ assertion = g_strdup_printf ("%s~%s.%s.%s", certificate, header_b64, body_b64, sig_b64);
- return cleartext;
+ g_free (body);
+ g_free (body_b64);
+ g_free (header_b64);
+ g_free (to_sign);
+ g_free (sig_b64);
+ g_free (sig);
+ g_free (digest_hex);
+ g_free (digest);
+ mpz_clear (signature);
+
+ return assertion;
+}
+
+static guint8 *
+ephy_sync_crypto_pad (const char *text,
+ gsize block_len,
+ gsize *out_len)
+{
+ guint8 *out;
+ gsize text_len = strlen (text);
+
+ g_assert (text);
+ g_assert (out_len);
+
+ if (text_len % block_len == 0)
+ *out_len = text_len;
+ else
+ *out_len = text_len + block_len - text_len % block_len;
+
+ out = g_malloc (*out_len);
+
+ if (text_len % block_len != 0)
+ memset (out, block_len - text_len % block_len, *out_len);
+
+ memcpy (out, text, text_len);
+
+ return out;
+}
+
+static guint8 *
+ephy_sync_crypto_aes_256_encrypt (const char *text,
+ const guint8 *key,
+ const guint8 *iv,
+ gsize *out_len)
+{
+ guint8 *padded;
+ guint8 *encrypted;
+ gsize padded_len;
+ struct CBC_CTX(struct aes256_ctx, AES_BLOCK_SIZE) ctx;
+
+ g_assert (text);
+ g_assert (key);
+ g_assert (iv);
+ g_assert (out_len);
+
+ padded = ephy_sync_crypto_pad (text, AES_BLOCK_SIZE, &padded_len);
+ encrypted = g_malloc (padded_len);
+
+ aes256_set_encrypt_key(&ctx.ctx, key);
+ CBC_SET_IV(&ctx, iv);
+ CBC_ENCRYPT(&ctx, aes256_encrypt, padded_len, encrypted, padded);
+
+ *out_len = padded_len;
+ g_free (padded);
+
+ return encrypted;
}
char *
@@ -1059,214 +1109,141 @@ ephy_sync_crypto_encrypt_record (const char *cleartext,
return payload;
}
-SyncCryptoHawkHeader *
-ephy_sync_crypto_compute_hawk_header (const char *url,
- const char *method,
- const char *id,
- const guint8 *key,
- gsize key_len,
- SyncCryptoHawkOptions *options)
+static gboolean
+ephy_sync_crypto_hmac_is_valid (const char *text,
+ const guint8 *key,
+ const char *expected)
{
- SyncCryptoHawkHeader *hawk_header;
- SyncCryptoHawkArtifacts *artifacts;
- SoupURI *uri;
- char *resource;
- char *hash;
- char *header;
- char *mac;
- char *nonce;
- char *payload;
- char *timestamp;
- guint8 *bytes;
- gint64 ts;
-
- g_return_val_if_fail (url, NULL);
- g_return_val_if_fail (method, NULL);
- g_return_val_if_fail (id, NULL);
- g_return_val_if_fail (key, NULL);
-
- ts = g_get_real_time () / 1000000;
- hash = options ? g_strdup (options->hash) : NULL;
- payload = options ? options->payload : NULL;
- timestamp = options ? options->timestamp : NULL;
- uri = soup_uri_new (url);
- resource = !soup_uri_get_query (uri) ? g_strdup (soup_uri_get_path (uri))
- : g_strconcat (soup_uri_get_path (uri),
- "?",
- soup_uri_get_query (uri),
- NULL);
-
- if (options && options->nonce) {
- nonce = g_strdup (options->nonce);
- } else {
- bytes = g_malloc (NONCE_LEN / 2);
- ephy_sync_utils_generate_random_bytes (NULL, NONCE_LEN / 2, bytes);
- nonce = ephy_sync_utils_encode_hex (bytes, NONCE_LEN / 2);
- g_free (bytes);
- }
-
- if (timestamp) {
- char *local_time_offset;
- gint64 offset;
-
- local_time_offset = options ? options->local_time_offset : NULL;
- offset = local_time_offset ? g_ascii_strtoll (local_time_offset, NULL, 10) : 0;
- ts = g_ascii_strtoll (timestamp, NULL, 10) + offset;
- }
-
- if (!hash && payload) {
- const char *content_type = options ? options->content_type : "text/plain";
-
- /* Calculate hash for the given payload. */
- hash = ephy_sync_crypto_calculate_payload_hash (payload, content_type);
- }
-
- /* Create artifacts from options. */
- artifacts = ephy_sync_crypto_hawk_artifacts_new (options ? options->app : NULL,
- options ? options->dlg : NULL,
- options ? options->ext : NULL,
- hash,
- soup_uri_get_host (uri),
- method,
- nonce,
- soup_uri_get_port (uri),
- resource,
- ts);
-
- header = g_strconcat ("Hawk id=\"", id, "\"",
- ", ts=\"", artifacts->ts, "\"",
- ", nonce=\"", artifacts->nonce, "\"",
- NULL);
-
- /* Append pre-calculated payload hash if any. */
- if (artifacts->hash && strlen (artifacts->hash) > 0)
- header = ephy_sync_crypto_append_to_header (header, "hash", artifacts->hash);
-
- /* Append the application specific data if any. */
- if (artifacts->ext && strlen (artifacts->ext) > 0) {
- char *h_ext;
- char *tmp_ext;
+ char *hmac;
+ gboolean retval;
- tmp_ext = ephy_sync_crypto_find_and_replace (artifacts->ext, "\\", "\\\\");
- h_ext = ephy_sync_crypto_find_and_replace (tmp_ext, "\n", "\\n");
- header = ephy_sync_crypto_append_to_header (header, "ext", h_ext);
+ g_assert (text);
+ g_assert (key);
+ g_assert (expected);
- g_free (h_ext);
- g_free (tmp_ext);
- }
+ /* SHA256 expects a 32 bytes key. */
+ hmac = g_compute_hmac_for_string (G_CHECKSUM_SHA256, key, 32, text, -1);
+ retval = g_strcmp0 (hmac, expected) == 0;
+ g_free (hmac);
- /* Calculate and append a message authentication code (MAC). */
- mac = ephy_sync_crypto_calculate_mac ("header", key, key_len, artifacts);
- header = ephy_sync_crypto_append_to_header (header, "mac", mac);
+ return retval;
+}
- /* Append the Oz application id if any. */
- if (artifacts->app) {
- header = ephy_sync_crypto_append_to_header (header, "app", artifacts->app);
+static char *
+ephy_sync_crypto_unpad (const guint8 *data,
+ gsize data_len,
+ gsize block_len)
+{
+ char *out;
+ gsize out_len;
+ gsize padding = data[data_len - 1];
- /* Append the Oz delegated-by application id if any. */
- if (artifacts->dlg)
- header = ephy_sync_crypto_append_to_header (header, "dlg", artifacts->dlg);
- }
+ g_assert (data);
- hawk_header = ephy_sync_crypto_hawk_header_new (header, artifacts);
+ if (padding >= 1 && padding <= block_len)
+ out_len = data_len - padding;
+ else
+ out_len = data_len;
- soup_uri_free (uri);
- g_free (hash);
- g_free (mac);
- g_free (nonce);
- g_free (resource);
- g_free (header);
+ out = g_malloc0 (out_len + 1);
+ memcpy (out, data, out_len);
- return hawk_header;
+ return out;
}
-SyncCryptoRSAKeyPair *
-ephy_sync_crypto_generate_rsa_key_pair (void)
+static char *
+ephy_sync_crypto_aes_256_decrypt (const guint8 *data,
+ gsize data_len,
+ const guint8 *key,
+ const guint8 *iv)
{
- struct rsa_public_key public;
- struct rsa_private_key private;
- int success;
+ guint8 *decrypted;
+ char *unpadded;
+ struct CBC_CTX(struct aes256_ctx, AES_BLOCK_SIZE) ctx;
- rsa_public_key_init (&public);
- rsa_private_key_init (&private);
+ g_assert (data);
+ g_assert (key);
+ g_assert (iv);
- /* The public exponent, usually one of the small Fermat primes 3, 5, 17, 257, 65537. */
- mpz_set_ui (public.e, 65537);
+ decrypted = g_malloc (data_len);
- /* Key sizes below 2048 are considered breakable and should not be used. */
- success = rsa_generate_keypair (&public, &private,
- NULL, ephy_sync_utils_generate_random_bytes,
- NULL, NULL, 2048, 0);
- /* Given correct parameters, this never fails. */
- g_assert (success);
+ aes256_set_decrypt_key (&ctx.ctx, key);
+ CBC_SET_IV (&ctx, iv);
+ CBC_DECRYPT (&ctx, aes256_decrypt, data_len, decrypted, data);
- return ephy_sync_crypto_rsa_key_pair_new (public, private);
+ unpadded = ephy_sync_crypto_unpad (decrypted, data_len, AES_BLOCK_SIZE);
+ g_free (decrypted);
+
+ return unpadded;
}
char *
-ephy_sync_crypto_create_assertion (const char *certificate,
- const char *audience,
- guint64 seconds,
- SyncCryptoRSAKeyPair *rsa_key_pair)
+ephy_sync_crypto_decrypt_record (const char *payload,
+ SyncCryptoKeyBundle *bundle)
{
- mpz_t signature;
- const char *header = "{\"alg\": \"RS256\"}";
- char *body;
- char *body_b64;
- char *header_b64;
- char *to_sign;
- char *sig_b64;
- char *assertion;
- char *digest_hex;
- guint8 *digest;
- guint8 *sig;
- guint64 expires_at;
- gsize expected_size;
- gsize count;
- int success;
-
- g_return_val_if_fail (certificate, NULL);
- g_return_val_if_fail (audience, NULL);
- g_return_val_if_fail (rsa_key_pair, NULL);
+ JsonNode *node = NULL;
+ JsonObject *json = NULL;
+ GError *error = NULL;
+ guint8 *aes_key = NULL;
+ guint8 *hmac_key = NULL;
+ guint8 *ciphertext = NULL;
+ guint8 *iv = NULL;
+ char *cleartext = NULL;
+ const char *ciphertext_b64;
+ const char *iv_b64;
+ const char *hmac;
+ gsize ciphertext_len;
+ gsize iv_len;
- /* Encode the header and body to base64 url safe and join them. */
- expires_at = g_get_real_time () / 1000 + seconds * 1000;
- body = g_strdup_printf ("{\"exp\": %lu, \"aud\": \"%s\"}", expires_at, audience);
- body_b64 = ephy_sync_utils_base64_urlsafe_encode ((guint8 *)body, strlen (body), TRUE);
- header_b64 = ephy_sync_utils_base64_urlsafe_encode ((guint8 *)header, strlen (header), TRUE);
- to_sign = g_strdup_printf ("%s.%s", header_b64, body_b64);
+ g_return_val_if_fail (payload, NULL);
+ g_return_val_if_fail (bundle, NULL);
- /* Compute the SHA256 hash of the message to be signed. */
- digest_hex = g_compute_checksum_for_string (G_CHECKSUM_SHA256, to_sign, -1);
- digest = ephy_sync_utils_decode_hex (digest_hex);
+ /* Extract ciphertext, iv and hmac from payload. */
+ node = json_from_string (payload, &error);
+ if (error) {
+ g_warning ("Payload is not a valid JSON: %s", error->message);
+ goto out;
+ }
+ json = json_node_get_object (node);
+ if (!json) {
+ g_warning ("JSON node does not hold a JSON object");
+ goto out;
+ }
+ ciphertext_b64 = json_object_get_string_member (json, "ciphertext");
+ iv_b64 = json_object_get_string_member (json, "IV");
+ hmac = json_object_get_string_member (json, "hmac");
+ if (!ciphertext_b64 || !iv_b64 || !hmac) {
+ g_warning ("JSON object has missing or invalid members");
+ goto out;
+ }
- /* Use the provided key pair to RSA sign the message. */
- mpz_init (signature);
- success = rsa_sha256_sign_digest_tr (&rsa_key_pair->public, &rsa_key_pair->private,
- NULL, ephy_sync_utils_generate_random_bytes,
- digest, signature);
- /* Given correct parameters, this never fails. */
- g_assert (success);
+ /* Get the encryption key and the HMAC key. */
+ aes_key = ephy_sync_utils_decode_hex (bundle->aes_key_hex);
+ hmac_key = ephy_sync_utils_decode_hex (bundle->hmac_key_hex);
- expected_size = (mpz_sizeinbase (signature, 2) + 7) / 8;
- sig = g_malloc (expected_size);
- mpz_export (sig, &count, 1, sizeof (guint8), 0, 0, signature);
- /* Given correct parameters, this never fails. */
- g_assert (count == expected_size);
+ /* Under no circumstances should a client try to decrypt a record
+ * if the HMAC verification fails.
+ */
+ if (!ephy_sync_crypto_hmac_is_valid (ciphertext_b64, hmac_key, hmac)) {
+ g_warning ("Incorrect HMAC value");
+ goto out;
+ }
- /* Join certificate, header, body and signed message to create the assertion. */
- sig_b64 = ephy_sync_utils_base64_urlsafe_encode (sig, count, TRUE);
- assertion = g_strdup_printf ("%s~%s.%s.%s", certificate, header_b64, body_b64, sig_b64);
+ /* Finally, decrypt the record. */
+ ciphertext = g_base64_decode (ciphertext_b64, &ciphertext_len);
+ iv = g_base64_decode (iv_b64, &iv_len);
+ cleartext = ephy_sync_crypto_aes_256_decrypt (ciphertext, ciphertext_len,
+ aes_key, iv);
- g_free (body);
- g_free (body_b64);
- g_free (header_b64);
- g_free (to_sign);
- g_free (sig_b64);
- g_free (sig);
- g_free (digest_hex);
- g_free (digest);
- mpz_clear (signature);
+out:
+ g_free (ciphertext);
+ g_free (iv);
+ g_free (aes_key);
+ g_free (hmac_key);
+ if (node)
+ json_node_unref (node);
+ if (error)
+ g_error_free (error);
- return assertion;
+ return cleartext;
}
diff --git a/lib/sync/ephy-sync-crypto.h b/lib/sync/ephy-sync-crypto.h
index 3b275ce8a..be52d6f08 100644
--- a/lib/sync/ephy-sync-crypto.h
+++ b/lib/sync/ephy-sync-crypto.h
@@ -66,55 +66,57 @@ typedef struct {
char *hmac_key_hex;
} SyncCryptoKeyBundle;
-SyncCryptoHawkOptions *ephy_sync_crypto_hawk_options_new (const char *app,
- const char *dlg,
- const char *ext,
- const char *content_type,
- const char *hash,
- const char *local_time_offset,
- const char *nonce,
- const char *payload,
- const char *timestamp);
-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 *rsa_key_pair);
-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 *key_fetch_token,
- guint8 **token_id,
- guint8 **req_hmac_key,
- guint8 **resp_hmac_key,
- guint8 **resp_xor_key,
- gsize token_len);
-void ephy_sync_crypto_process_session_token (const char *session_token,
- guint8 **token_id,
- guint8 **req_hmac_key,
- guint8 **requestKey,
- gsize token_len);
-gboolean ephy_sync_crypto_compute_sync_keys (const char *bundle_hex,
- const guint8 *resp_hmac_key,
- const guint8 *resp_xor_key,
- const guint8 *unwrap_b_key,
- guint8 **key_a,
- guint8 **key_b,
- gsize key_len);
-SyncCryptoKeyBundle *ephy_sync_crypto_derive_key_bundle (const guint8 *key,
- gsize key_len);
-char *ephy_sync_crypto_generate_crypto_keys (gsize key_len);
-char *ephy_sync_crypto_decrypt_record (const char *payload,
- SyncCryptoKeyBundle *bundle);
-char *ephy_sync_crypto_encrypt_record (const char *cleartext,
- SyncCryptoKeyBundle *bundle);
-SyncCryptoHawkHeader *ephy_sync_crypto_compute_hawk_header (const char *url,
- const char *method,
- const char *id,
- const guint8 *key,
- gsize key_len,
- SyncCryptoHawkOptions *options);
-SyncCryptoRSAKeyPair *ephy_sync_crypto_generate_rsa_key_pair (void);
-char *ephy_sync_crypto_create_assertion (const char *certificate,
- const char *audience,
- guint64 duration,
- SyncCryptoRSAKeyPair *rsa_key_pair);
+SyncCryptoHawkOptions *ephy_sync_crypto_hawk_options_new (const char *app,
+ const char *dlg,
+ const char *ext,
+ const char *content_type,
+ const char *hash,
+ const char *local_time_offset,
+ const char *nonce,
+ const char *payload,
+ const char *timestamp);
+void ephy_sync_crypto_hawk_options_free (SyncCryptoHawkOptions *options);
+
+SyncCryptoHawkHeader *ephy_sync_crypto_hawk_header_new (const char *url,
+ const char *method,
+ const char *id,
+ const guint8 *key,
+ gsize key_len,
+ SyncCryptoHawkOptions *options);
+void ephy_sync_crypto_hawk_header_free (SyncCryptoHawkHeader *header);
+
+SyncCryptoRSAKeyPair *ephy_sync_crypto_rsa_key_pair_new (void);
+void ephy_sync_crypto_rsa_key_pair_free (SyncCryptoRSAKeyPair *key_pair);
+
+SyncCryptoKeyBundle *ephy_sync_crypto_key_bundle_new (JsonArray *array);
+void ephy_sync_crypto_key_bundle_free (SyncCryptoKeyBundle *bundle);
+
+void ephy_sync_crypto_derive_session_token (const char *session_token,
+ guint8 **token_id,
+ guint8 **req_hmac_key,
+ guint8 **requestKey);
+void ephy_sync_crypto_derive_key_fetch_token (const char *key_fetch_token,
+ guint8 **token_id,
+ guint8 **req_hmac_key,
+ guint8 **resp_hmac_key,
+ guint8 **resp_xor_key);
+gboolean ephy_sync_crypto_derive_master_keys (const char *bundle_hex,
+ const guint8 *resp_hmac_key,
+ const guint8 *resp_xor_key,
+ const guint8 *unwrap_kb,
+ guint8 **ka,
+ guint8 **kb);
+SyncCryptoKeyBundle *ephy_sync_crypto_derive_master_bundle (const guint8 *kb);
+
+char *ephy_sync_crypto_generate_crypto_keys (void);
+char *ephy_sync_crypto_create_assertion (const char *certificate,
+ const char *audience,
+ guint64 duration,
+ SyncCryptoRSAKeyPair *key_pair);
+
+char *ephy_sync_crypto_encrypt_record (const char *cleartext,
+ SyncCryptoKeyBundle *bundle);
+char *ephy_sync_crypto_decrypt_record (const char *payload,
+ SyncCryptoKeyBundle *bundle);
G_END_DECLS
diff --git a/lib/sync/ephy-sync-service.c b/lib/sync/ephy-sync-service.c
index 9279f045f..64d70e696 100644
--- a/lib/sync/ephy-sync-service.c
+++ b/lib/sync/ephy-sync-service.c
@@ -52,7 +52,7 @@ struct _EphySyncService {
GQueue *storage_queue;
char *certificate;
- SyncCryptoRSAKeyPair *rsa_key_pair;
+ SyncCryptoRSAKeyPair *key_pair;
gboolean sync_periodically;
gboolean is_signing_in;
@@ -107,7 +107,7 @@ typedef struct {
char *email;
char *uid;
char *session_token;
- char *unwrap_b_key;
+ char *unwrap_kb;
char *token_id_hex;
guint8 *req_hmac_key;
guint8 *resp_hmac_key;
@@ -168,7 +168,7 @@ sign_in_async_data_new (EphySyncService *service,
const char *email,
const char *uid,
const char *session_token,
- const char *unwrap_b_key,
+ const char *unwrap_kb,
const char *token_id_hex,
const guint8 *req_hmac_key,
const guint8 *resp_hmac_key,
@@ -181,7 +181,7 @@ sign_in_async_data_new (EphySyncService *service,
data->email = g_strdup (email);
data->uid = g_strdup (uid);
data->session_token = g_strdup (session_token);
- data->unwrap_b_key = g_strdup (unwrap_b_key);
+ data->unwrap_kb = g_strdup (unwrap_kb);
data->token_id_hex = g_strdup (token_id_hex);
data->req_hmac_key = g_malloc (32);
memcpy (data->req_hmac_key, req_hmac_key, 32);
@@ -202,7 +202,7 @@ sign_in_async_data_free (SignInAsyncData *data)
g_free (data->email);
g_free (data->uid);
g_free (data->session_token);
- g_free (data->unwrap_b_key);
+ g_free (data->unwrap_kb);
g_free (data->token_id_hex);
g_free (data->req_hmac_key);
g_free (data->resp_hmac_key);
@@ -346,7 +346,7 @@ ephy_sync_service_get_key_bundle (EphySyncService *self,
array = json_object_has_member (collections, collection) ?
json_object_get_array_member (collections, collection) :
json_object_get_array_member (json, "default");
- bundle = ephy_sync_crypto_key_bundle_from_array (array);
+ bundle = ephy_sync_crypto_key_bundle_new (array);
json_node_unref (node);
@@ -381,17 +381,17 @@ ephy_sync_service_storage_credentials_is_expired (EphySyncService *self)
}
static void
-ephy_sync_service_fxa_hawk_post_async (EphySyncService *self,
- const char *endpoint,
- const char *id,
- guint8 *key,
- gsize key_len,
- char *request_body,
- SoupSessionCallback callback,
- gpointer user_data)
-{
- SyncCryptoHawkOptions *hawk_options;
- SyncCryptoHawkHeader *hawk_header;
+ephy_sync_service_fxa_hawk_post (EphySyncService *self,
+ const char *endpoint,
+ const char *id,
+ guint8 *key,
+ gsize key_len,
+ const char *request_body,
+ SoupSessionCallback callback,
+ gpointer user_data)
+{
+ SyncCryptoHawkOptions *options;
+ SyncCryptoHawkHeader *header;
SoupMessage *msg;
char *url;
const char *content_type = "application/json; charset=utf-8";
@@ -407,35 +407,29 @@ ephy_sync_service_fxa_hawk_post_async (EphySyncService *self,
soup_message_set_request (msg, content_type, SOUP_MEMORY_COPY,
request_body, strlen (request_body));
- hawk_options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL,
- content_type,
- NULL, NULL, NULL,
- request_body,
- NULL);
- hawk_header = ephy_sync_crypto_compute_hawk_header (url, "POST", id,
- key, key_len,
- hawk_options);
- soup_message_headers_append (msg->request_headers,
- "authorization", hawk_header->header);
- soup_message_headers_append (msg->request_headers,
- "content-type", content_type);
+ options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL, content_type,
+ NULL, NULL, NULL, request_body,
+ NULL);
+ header = ephy_sync_crypto_hawk_header_new (url, "POST", id, key, key_len, options);
+ soup_message_headers_append (msg->request_headers, "authorization", header->header);
+ soup_message_headers_append (msg->request_headers, "content-type", content_type);
soup_session_queue_message (self->session, msg, callback, user_data);
g_free (url);
- ephy_sync_crypto_hawk_options_free (hawk_options);
- ephy_sync_crypto_hawk_header_free (hawk_header);
+ ephy_sync_crypto_hawk_options_free (options);
+ ephy_sync_crypto_hawk_header_free (header);
}
static void
-ephy_sync_service_fxa_hawk_get_async (EphySyncService *self,
- const char *endpoint,
- const char *id,
- guint8 *key,
- gsize key_len,
- SoupSessionCallback callback,
- gpointer user_data)
-{
- SyncCryptoHawkHeader *hawk_header;
+ephy_sync_service_fxa_hawk_get (EphySyncService *self,
+ const char *endpoint,
+ const char *id,
+ guint8 *key,
+ gsize key_len,
+ SoupSessionCallback callback,
+ gpointer user_data)
+{
+ SyncCryptoHawkHeader *header;
SoupMessage *msg;
char *url;
@@ -446,22 +440,20 @@ ephy_sync_service_fxa_hawk_get_async (EphySyncService *self,
url = g_strdup_printf ("%s/%s", FIREFOX_ACCOUNTS_SERVER_URL, endpoint);
msg = soup_message_new (SOUP_METHOD_GET, url);
- hawk_header = ephy_sync_crypto_compute_hawk_header (url, "GET", id,
- key, key_len,
- NULL);
- soup_message_headers_append (msg->request_headers, "authorization", hawk_header->header);
+ header = ephy_sync_crypto_hawk_header_new (url, "GET", id, key, key_len, NULL);
+ soup_message_headers_append (msg->request_headers, "authorization", header->header);
soup_session_queue_message (self->session, msg, callback, user_data);
g_free (url);
- ephy_sync_crypto_hawk_header_free (hawk_header);
+ ephy_sync_crypto_hawk_header_free (header);
}
static void
ephy_sync_service_send_storage_request (EphySyncService *self,
StorageRequestAsyncData *data)
{
- SyncCryptoHawkOptions *hawk_options = NULL;
- SyncCryptoHawkHeader *hawk_header;
+ SyncCryptoHawkOptions *options = NULL;
+ SyncCryptoHawkHeader *header;
SoupMessage *msg;
char *url;
char *if_modified_since = NULL;
@@ -475,53 +467,46 @@ ephy_sync_service_send_storage_request (EphySyncService *self,
msg = soup_message_new (data->method, url);
if (data->request_body) {
- hawk_options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL,
- content_type,
- NULL, NULL, NULL,
- data->request_body,
- NULL);
+ options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL, content_type,
+ NULL, NULL, NULL, data->request_body,
+ NULL);
soup_message_set_request (msg, content_type, SOUP_MEMORY_COPY,
data->request_body, strlen (data->request_body));
}
if (!g_strcmp0 (data->method, SOUP_METHOD_PUT))
- soup_message_headers_append (msg->request_headers,
- "content-type", content_type);
+ soup_message_headers_append (msg->request_headers, "content-type", content_type);
if (data->modified_since >= 0) {
if_modified_since = g_strdup_printf ("%.2lf", data->modified_since);
- soup_message_headers_append (msg->request_headers,
- "X-If-Modified-Since", if_modified_since);
+ soup_message_headers_append (msg->request_headers, "X-If-Modified-Since", if_modified_since);
}
if (data->unmodified_since >= 0) {
if_unmodified_since = g_strdup_printf ("%.2lf", data->unmodified_since);
- soup_message_headers_append (msg->request_headers,
- "X-If-Unmodified-Since", if_unmodified_since);
+ soup_message_headers_append (msg->request_headers, "X-If-Unmodified-Since", if_unmodified_since);
}
- hawk_header = ephy_sync_crypto_compute_hawk_header (url, data->method,
- self->storage_credentials_id,
- (guint8 *)self->storage_credentials_key,
- strlen (self->storage_credentials_key),
- hawk_options);
- soup_message_headers_append (msg->request_headers,
- "authorization", hawk_header->header);
+ header = ephy_sync_crypto_hawk_header_new (url, data->method,
+ self->storage_credentials_id,
+ (guint8 *)self->storage_credentials_key,
+ strlen (self->storage_credentials_key),
+ options);
+ soup_message_headers_append (msg->request_headers, "authorization", header->header);
soup_session_queue_message (self->session, msg, data->callback, data->user_data);
- if (hawk_options)
- ephy_sync_crypto_hawk_options_free (hawk_options);
-
g_free (url);
g_free (if_modified_since);
g_free (if_unmodified_since);
- ephy_sync_crypto_hawk_header_free (hawk_header);
+ ephy_sync_crypto_hawk_header_free (header);
+ if (options)
+ ephy_sync_crypto_hawk_options_free (options);
storage_request_async_data_free (data);
}
static gboolean
-ephy_sync_service_certificate_is_valid (EphySyncService *self,
- const char *certificate)
+ephy_sync_service_verify_certificate (EphySyncService *self,
+ const char *certificate)
{
JsonParser *parser;
JsonObject *json;
@@ -668,12 +653,12 @@ static void
ephy_sync_service_destroy_session (EphySyncService *self,
const char *session_token)
{
- SyncCryptoHawkOptions *hawk_options;
- SyncCryptoHawkHeader *hawk_header;
+ SyncCryptoHawkOptions *options;
+ SyncCryptoHawkHeader *header;
SoupMessage *msg;
guint8 *token_id;
guint8 *req_hmac_key;
- guint8 *request_key;
+ guint8 *tmp;
char *token_id_hex;
char *url;
const char *content_type = "application/json; charset=utf-8";
@@ -685,34 +670,29 @@ ephy_sync_service_destroy_session (EphySyncService *self,
g_assert (session_token);
url = g_strdup_printf ("%s/session/destroy", FIREFOX_ACCOUNTS_SERVER_URL);
- ephy_sync_crypto_process_session_token (session_token, &token_id,
- &req_hmac_key, &request_key, 32);
+ ephy_sync_crypto_derive_session_token (session_token, &token_id,
+ &req_hmac_key, &tmp);
token_id_hex = ephy_sync_utils_encode_hex (token_id, 32);
msg = soup_message_new (SOUP_METHOD_POST, url);
soup_message_set_request (msg, content_type, SOUP_MEMORY_STATIC,
request_body, strlen (request_body));
- hawk_options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL,
- content_type,
- NULL, NULL, NULL,
- request_body,
- NULL);
- hawk_header = ephy_sync_crypto_compute_hawk_header (url, "POST", token_id_hex,
- req_hmac_key, 32,
- hawk_options);
- soup_message_headers_append (msg->request_headers,
- "authorization", hawk_header->header);
- soup_message_headers_append (msg->request_headers,
- "content-type", content_type);
+ options = ephy_sync_crypto_hawk_options_new (NULL, NULL, NULL, content_type,
+ NULL, NULL, NULL, request_body,
+ NULL);
+ header = ephy_sync_crypto_hawk_header_new (url, "POST", token_id_hex,
+ req_hmac_key, 32, options);
+ soup_message_headers_append (msg->request_headers, "authorization", header->header);
+ soup_message_headers_append (msg->request_headers, "content-type", content_type);
soup_session_queue_message (self->session, msg, destroy_session_cb, self);
g_free (token_id_hex);
g_free (token_id);
g_free (req_hmac_key);
- g_free (request_key);
+ g_free (tmp);
g_free (url);
- ephy_sync_crypto_hawk_options_free (hawk_options);
- ephy_sync_crypto_hawk_header_free (hawk_header);
+ ephy_sync_crypto_hawk_options_free (options);
+ ephy_sync_crypto_hawk_header_free (header);
}
static void
@@ -736,9 +716,9 @@ ephy_sync_service_report_sign_in_error (EphySyncService *self,
}
static void
-obtain_storage_credentials_cb (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
+get_storage_credentials_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
{
EphySyncService *self = EPHY_SYNC_SERVICE (user_data);
JsonNode *node = NULL;
@@ -800,11 +780,11 @@ out:
}
static void
-ephy_sync_service_obtain_storage_credentials (EphySyncService *self)
+ephy_sync_service_trade_browserid_assertion (EphySyncService *self)
{
SoupMessage *msg;
- guint8 *key_b;
- char *hashed_key_b;
+ guint8 *kb;
+ char *hashed_kb;
char *client_state;
char *audience;
char *assertion;
@@ -812,25 +792,26 @@ ephy_sync_service_obtain_storage_credentials (EphySyncService *self)
g_assert (EPHY_IS_SYNC_SERVICE (self));
g_assert (self->certificate);
- g_assert (self->rsa_key_pair);
+ g_assert (self->key_pair);
audience = ephy_sync_utils_get_audience (TOKEN_SERVER_URL);
assertion = ephy_sync_crypto_create_assertion (self->certificate, audience,
- 300, self->rsa_key_pair);
- key_b = ephy_sync_utils_decode_hex (ephy_sync_service_get_secret (self, secrets[MASTER_KEY]));
- hashed_key_b = g_compute_checksum_for_data (G_CHECKSUM_SHA256, key_b, 32);
- client_state = g_strndup (hashed_key_b, 32);
+ 300, self->key_pair);
+ kb = ephy_sync_utils_decode_hex (ephy_sync_service_get_secret (self, secrets[MASTER_KEY]));
+ hashed_kb = g_compute_checksum_for_data (G_CHECKSUM_SHA256, kb, 32);
+ client_state = g_strndup (hashed_kb, 32);
authorization = g_strdup_printf ("BrowserID %s", assertion);
msg = soup_message_new (SOUP_METHOD_GET, TOKEN_SERVER_URL);
/* We need to add the X-Client-State header so that the Token Server will
- * recognize accounts that were previously used to sync Firefox data too. */
+ * recognize accounts that were previously used to sync Firefox data too.
+ */
soup_message_headers_append (msg->request_headers, "X-Client-State", client_state);
soup_message_headers_append (msg->request_headers, "authorization", authorization);
- soup_session_queue_message (self->session, msg, obtain_storage_credentials_cb, self);
+ soup_session_queue_message (self->session, msg, get_storage_credentials_cb, self);
- g_free (key_b);
- g_free (hashed_key_b);
+ g_free (kb);
+ g_free (hashed_kb);
g_free (client_state);
g_free (audience);
g_free (assertion);
@@ -838,9 +819,9 @@ ephy_sync_service_obtain_storage_credentials (EphySyncService *self)
}
static void
-obtain_signed_certificate_cb (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
+get_signed_certificate_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
{
EphySyncService *self = EPHY_SYNC_SERVICE (user_data);
JsonNode *node = NULL;
@@ -867,24 +848,27 @@ obtain_signed_certificate_cb (SoupSession *session,
g_warning ("JSON object has missing or invalid 'cert' member");
goto out_error;
}
- if (!ephy_sync_service_certificate_is_valid (self, certificate)) {
+
+ if (!ephy_sync_service_verify_certificate (self, certificate)) {
g_warning ("Invalid certificate");
- ephy_sync_crypto_rsa_key_pair_free (self->rsa_key_pair);
+ ephy_sync_crypto_rsa_key_pair_free (self->key_pair);
goto out_error;
}
+
self->certificate = g_strdup (certificate);
- ephy_sync_service_obtain_storage_credentials (self);
+ ephy_sync_service_trade_browserid_assertion (self);
goto out_no_error;
}
/* Since a new Firefox Account password implies new tokens, this will fail
* with an error code 110 (Invalid authentication token in request signature)
* if the user has changed his password since the last time he signed in.
- * When this happens, notify the user to sign in with the new password. */
+ * When this happens, notify the user to sign in with the new password.
+ */
if (json_object_get_int_member (json, "errno") == 110) {
message = _("The password of your Firefox account seems to have been changed.");
suggestion = _("Please visit Preferences and sign in with the new password to continue syncing.");
- ephy_sync_service_do_sign_out (self);
+ ephy_sync_service_sign_out (self);
}
g_warning ("Failed to sign certificate. Status code: %u, response: %s",
@@ -906,14 +890,14 @@ out_no_error:
}
static void
-ephy_sync_service_obtain_signed_certificate (EphySyncService *self)
+ephy_sync_service_get_storage_credentials (EphySyncService *self)
{
JsonNode *node;
JsonObject *object_key;
JsonObject *object_body;
guint8 *token_id;
guint8 *req_hmac_key;
- guint8 *request_key;
+ guint8 *tmp;
const char *session_token;
char *token_id_hex;
char *request_body;
@@ -922,19 +906,24 @@ ephy_sync_service_obtain_signed_certificate (EphySyncService *self)
g_assert (EPHY_IS_SYNC_SERVICE (self));
+ /* To get the storage credentials from the Token Server, we need to create a
+ * BrowserID assertion. For that we need to obtain an identity certificate
+ * signed by the Firefox Accounts Server.
+ */
+
/* Generate a new RSA key pair to sign the new certificate. */
- if (self->rsa_key_pair)
- ephy_sync_crypto_rsa_key_pair_free (self->rsa_key_pair);
- self->rsa_key_pair = ephy_sync_crypto_generate_rsa_key_pair ();
+ if (self->key_pair)
+ ephy_sync_crypto_rsa_key_pair_free (self->key_pair);
+ self->key_pair = ephy_sync_crypto_rsa_key_pair_new ();
- /* Derive tokenID, reqHMACkey and requestKey from sessionToken. */
+ /* Derive tokenID and reqHMACkey from sessionToken. */
session_token = ephy_sync_service_get_secret (self, secrets[SESSION_TOKEN]);
- ephy_sync_crypto_process_session_token (session_token, &token_id,
- &req_hmac_key, &request_key, 32);
+ ephy_sync_crypto_derive_session_token (session_token, &token_id,
+ &req_hmac_key, &tmp);
token_id_hex = ephy_sync_utils_encode_hex (token_id, 32);
- n = mpz_get_str (NULL, 10, self->rsa_key_pair->public.n);
- e = mpz_get_str (NULL, 10, self->rsa_key_pair->public.e);
+ n = mpz_get_str (NULL, 10, self->key_pair->public.n);
+ e = mpz_get_str (NULL, 10, self->key_pair->public.e);
node = json_node_new (JSON_NODE_OBJECT);
object_body = json_object_new ();
/* Milliseconds, limited to 24 hours. */
@@ -946,9 +935,9 @@ ephy_sync_service_obtain_signed_certificate (EphySyncService *self)
json_object_set_object_member (object_body, "publicKey", object_key);
json_node_set_object (node, object_body);
request_body = json_to_string (node, FALSE);
- ephy_sync_service_fxa_hawk_post_async (self, "certificate/sign", token_id_hex,
- req_hmac_key, 32, request_body,
- obtain_signed_certificate_cb, self);
+ ephy_sync_service_fxa_hawk_post (self, "certificate/sign", token_id_hex,
+ req_hmac_key, 32, request_body,
+ get_signed_certificate_cb, self);
g_free (request_body);
json_object_unref (object_body);
@@ -956,7 +945,7 @@ ephy_sync_service_obtain_signed_certificate (EphySyncService *self)
g_free (e);
g_free (n);
g_free (token_id_hex);
- g_free (request_key);
+ g_free (tmp);
g_free (req_hmac_key);
g_free (token_id);
}
@@ -983,17 +972,19 @@ ephy_sync_service_queue_storage_request (EphySyncService *self,
/* If the storage credentials are valid, then directly send the request.
* Otherwise, the request will remain queued and scheduled to be sent when
- * the new credentials are obtained. */
+ * the new credentials are obtained.
+ */
if (!ephy_sync_service_storage_credentials_is_expired (self)) {
ephy_sync_service_send_storage_request (self, data);
} else {
g_queue_push_tail (self->storage_queue, data);
if (!self->locked) {
- /* Mark as locked so other requests won't lead to conflicts while obtaining
- * new storage credentials. */
+ /* Mark as locked so other requests won't lead to conflicts while
+ * obtaining new storage credentials.
+ */
self->locked = TRUE;
ephy_sync_service_clear_storage_credentials (self);
- ephy_sync_service_obtain_signed_certificate (self);
+ ephy_sync_service_get_storage_credentials (self);
}
}
}
@@ -1035,7 +1026,8 @@ ephy_sync_service_delete_synchronizable (EphySyncService *self,
collection = ephy_synchronizable_manager_get_collection_name (manager);
id = ephy_synchronizable_get_id (synchronizable);
/* Firefox uses UUIDs with curly braces as IDs for saved passwords records.
- * Curly braces are unsafe characters in URLs so they must be encoded. */
+ * Curly braces are unsafe characters in URLs so they must be encoded.
+ */
id_safe = soup_uri_encode (id, NULL);
endpoint = g_strdup_printf ("storage/%s/%s", collection, id_safe);
@@ -1138,7 +1130,8 @@ ephy_sync_service_download_synchronizable (EphySyncService *self,
id = ephy_synchronizable_get_id (synchronizable);
collection = ephy_synchronizable_manager_get_collection_name (manager);
/* Firefox uses UUIDs with curly braces as IDs for saved passwords records.
- * Curly braces are unsafe characters in URLs so they must be encoded. */
+ * Curly braces are unsafe characters in URLs so they must be encoded.
+ */
id_safe = soup_uri_encode (id, NULL);
endpoint = g_strdup_printf ("storage/%s/%s", collection, id_safe);
data = sync_async_data_new (self, manager, synchronizable);
@@ -1160,8 +1153,9 @@ upload_synchronizable_cb (SoupSession *session,
SyncAsyncData *data = (SyncAsyncData *)user_data;
double time_modified;
- /* Code 412 means that there is a more recent version of the object
- * on the server. Download it. */
+ /* Code 412 means that there is a more recent version on the server.
+ * Download it.
+ */
if (msg->status_code == 412) {
LOG ("Found a newer version of the object on the server, downloading it...");
ephy_sync_service_download_synchronizable (data->service, data->manager, data->synchronizable);
@@ -1204,7 +1198,8 @@ ephy_sync_service_upload_synchronizable (EphySyncService *self,
bso = ephy_synchronizable_to_bso (synchronizable, bundle);
id = ephy_synchronizable_get_id (synchronizable);
/* Firefox uses UUIDs with curly braces as IDs for saved passwords records.
- * Curly braces are unsafe characters in URLs so they must be encoded. */
+ * Curly braces are unsafe characters in URLs so they must be encoded.
+ */
id_safe = soup_uri_encode (id, NULL);
endpoint = g_strdup_printf ("storage/%s/%s", collection, id_safe);
data = sync_async_data_new (self, manager, synchronizable);
@@ -1351,9 +1346,8 @@ ephy_sync_service_sync_collection (EphySyncService *self,
}
static gboolean
-ephy_sync_service_sync (gpointer user_data)
+ephy_sync_service_sync_internal (EphySyncService *self)
{
- EphySyncService *self = EPHY_SYNC_SERVICE (user_data);
guint index = 0;
guint num_managers;
@@ -1374,17 +1368,6 @@ ephy_sync_service_sync (gpointer user_data)
}
static void
-ephy_sync_service_stop_periodical_sync (EphySyncService *self)
-{
- g_assert (EPHY_IS_SYNC_SERVICE (self));
-
- if (self->source_id != 0) {
- g_source_remove (self->source_id);
- self->source_id = 0;
- }
-}
-
-static void
ephy_sync_service_schedule_periodical_sync (EphySyncService *self)
{
guint seconds;
@@ -1392,12 +1375,25 @@ ephy_sync_service_schedule_periodical_sync (EphySyncService *self)
g_assert (EPHY_IS_SYNC_SERVICE (self));
seconds = ephy_sync_utils_get_sync_frequency () * 60;
- self->source_id = g_timeout_add_seconds (seconds, ephy_sync_service_sync, self);
+ self->source_id = g_timeout_add_seconds (seconds,
+ (GSourceFunc)ephy_sync_service_sync_internal,
+ self);
LOG ("Scheduled new sync with frequency %u minutes", seconds / 60);
}
static void
+ephy_sync_service_stop_periodical_sync (EphySyncService *self)
+{
+ g_assert (EPHY_IS_SYNC_SERVICE (self));
+
+ if (self->source_id != 0) {
+ g_source_remove (self->source_id);
+ self->source_id = 0;
+ }
+}
+
+static void
sync_frequency_changed_cb (GSettings *settings,
char *key,
EphySyncService *self)
@@ -1450,7 +1446,7 @@ load_secrets_cb (SecretService *service,
json_object_get_string_member (object, l->data));
if (self->sync_periodically)
- ephy_sync_service_start_periodical_sync (self);
+ ephy_sync_service_start_sync (self);
goto out_no_error;
out_error:
@@ -1565,7 +1561,7 @@ ephy_sync_service_dispose (GObject *object)
ephy_sync_service_clear_storage_credentials (self);
g_clear_object (&self->session);
- g_clear_pointer (&self->rsa_key_pair, ephy_sync_crypto_rsa_key_pair_free);
+ g_clear_pointer (&self->key_pair, ephy_sync_crypto_rsa_key_pair_free);
g_clear_pointer (&self->secrets, g_hash_table_destroy);
g_clear_pointer (&self->managers, g_slist_free);
g_queue_free_full (self->storage_queue, (GDestroyNotify)storage_request_async_data_free);
@@ -1656,7 +1652,7 @@ ephy_sync_service_new (gboolean sync_periodically)
}
static char *
-ephy_sync_service_upload_crypto_keys_record (EphySyncService *self)
+ephy_sync_service_upload_crypto_keys (EphySyncService *self)
{
SyncCryptoKeyBundle *bundle;
JsonNode *node;
@@ -1664,18 +1660,18 @@ ephy_sync_service_upload_crypto_keys_record (EphySyncService *self)
char *payload_clear;
char *payload_cipher;
char *body;
- const char *master_key_hex;
- guint8 *master_key;
+ const char *kb_hex;
+ guint8 *kb;
g_assert (EPHY_IS_SYNC_SERVICE (self));
- master_key_hex = ephy_sync_service_get_secret (self, secrets[MASTER_KEY]);
- g_assert (master_key_hex);
+ kb_hex = ephy_sync_service_get_secret (self, secrets[MASTER_KEY]);
+ g_assert (kb_hex);
node = json_node_new (JSON_NODE_OBJECT);
record = json_object_new ();
- payload_clear = ephy_sync_crypto_generate_crypto_keys (32);
- master_key = ephy_sync_utils_decode_hex (master_key_hex);
- bundle = ephy_sync_crypto_derive_key_bundle (master_key, 32);
+ payload_clear = ephy_sync_crypto_generate_crypto_keys ();
+ kb = ephy_sync_utils_decode_hex (kb_hex);
+ bundle = ephy_sync_crypto_derive_master_bundle (kb);
payload_cipher = ephy_sync_crypto_encrypt_record (payload_clear, bundle);
json_object_set_string_member (record, "payload", payload_cipher);
json_object_set_string_member (record, "id", "keys");
@@ -1688,7 +1684,7 @@ ephy_sync_service_upload_crypto_keys_record (EphySyncService *self)
g_free (body);
g_free (payload_cipher);
- g_free (master_key);
+ g_free (kb);
json_object_unref (record);
json_node_unref (node);
ephy_sync_crypto_key_bundle_free (bundle);
@@ -1697,9 +1693,9 @@ ephy_sync_service_upload_crypto_keys_record (EphySyncService *self)
}
static void
-obtain_crypto_keys_cb (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
+get_crypto_keys_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
{
EphySyncService *self = EPHY_SYNC_SERVICE (user_data);
SyncCryptoKeyBundle *bundle = NULL;
@@ -1708,10 +1704,10 @@ obtain_crypto_keys_cb (SoupSession *session,
GError *error = NULL;
const char *payload;
char *crypto_keys = NULL;
- guint8 *key_b = NULL;
+ guint8 *kb = NULL;
if (msg->status_code == 404) {
- crypto_keys = ephy_sync_service_upload_crypto_keys_record (self);
+ crypto_keys = ephy_sync_service_upload_crypto_keys (self);
goto store_secrets;
}
@@ -1738,9 +1734,10 @@ obtain_crypto_keys_cb (SoupSession *session,
}
/* Derive the Sync Key bundle from kB. The bundle consists of two 32 bytes keys:
* the first one used as a symmetric encryption key (AES) and the second one
- * used as a HMAC key. */
- key_b = ephy_sync_utils_decode_hex (ephy_sync_service_get_secret (self, secrets[MASTER_KEY]));
- bundle = ephy_sync_crypto_derive_key_bundle (key_b, 32);
+ * used as a HMAC key.
+ */
+ kb = ephy_sync_utils_decode_hex (ephy_sync_service_get_secret (self, secrets[MASTER_KEY]));
+ bundle = ephy_sync_crypto_derive_master_bundle (kb);
crypto_keys = ephy_sync_crypto_decrypt_record (payload, bundle);
if (!crypto_keys) {
g_warning ("Failed to decrypt crypto/keys record");
@@ -1762,17 +1759,17 @@ out_no_error:
if (error)
g_error_free (error);
g_free (crypto_keys);
- g_free (key_b);
+ g_free (kb);
}
static void
-ephy_sync_service_obtain_crypto_keys (EphySyncService *self)
+ephy_sync_service_get_crypto_keys (EphySyncService *self)
{
g_assert (EPHY_IS_SYNC_SERVICE (self));
ephy_sync_service_queue_storage_request (self, "storage/crypto/keys",
SOUP_METHOD_GET, NULL, -1, -1,
- obtain_crypto_keys_cb, self);
+ get_crypto_keys_cb, self);
}
static JsonObject *
@@ -1792,7 +1789,7 @@ make_engine_object (int version)
}
static void
-ephy_sync_service_upload_meta_global_record (EphySyncService *self)
+ephy_sync_service_upload_meta_global (EphySyncService *self)
{
JsonNode *node;
JsonObject *record;
@@ -1842,9 +1839,9 @@ ephy_sync_service_upload_meta_global_record (EphySyncService *self)
}
static void
-check_storage_version_cb (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
+verify_storage_version_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
{
EphySyncService *self = EPHY_SYNC_SERVICE (user_data);
JsonParser *parser = NULL;
@@ -1855,7 +1852,7 @@ check_storage_version_cb (SoupSession *session,
int storage_version;
if (msg->status_code == 404) {
- ephy_sync_service_upload_meta_global_record (self);
+ ephy_sync_service_upload_meta_global (self);
goto obtain_crypto_keys;
}
@@ -1906,7 +1903,7 @@ check_storage_version_cb (SoupSession *session,
}
obtain_crypto_keys:
- ephy_sync_service_obtain_crypto_keys (self);
+ ephy_sync_service_get_crypto_keys (self);
goto out_no_error;
out_error:
message = message ? message : _("Failed to verify storage version.");
@@ -1921,34 +1918,34 @@ out_no_error:
}
static void
-ephy_sync_service_check_storage_version (EphySyncService *self)
+ephy_sync_service_verify_storage_version (EphySyncService *self)
{
g_assert (EPHY_IS_SYNC_SERVICE (self));
ephy_sync_service_queue_storage_request (self, "storage/meta/global",
SOUP_METHOD_GET, NULL, -1, -1,
- check_storage_version_cb, self);
+ verify_storage_version_cb, self);
}
static void
-ephy_sync_service_conclude_sign_in (EphySyncService *self,
- SignInAsyncData *data,
- const char *bundle)
+ephy_sync_service_sign_in_finish (EphySyncService *self,
+ SignInAsyncData *data,
+ const char *bundle)
{
- guint8 *unwrap_key_b;
- guint8 *key_a;
- guint8 *key_b;
- char *key_b_hex;
+ guint8 *unwrap_kb;
+ guint8 *ka;
+ guint8 *kb;
+ char *kb_hex;
g_assert (EPHY_IS_SYNC_SERVICE (self));
g_assert (data);
g_assert (bundle);
/* Derive the master sync keys form the key bundle. */
- unwrap_key_b = ephy_sync_utils_decode_hex (data->unwrap_b_key);
- if (!ephy_sync_crypto_compute_sync_keys (bundle, data->resp_hmac_key,
- data->resp_xor_key, unwrap_key_b,
- &key_a, &key_b, 32)) {
+ unwrap_kb = ephy_sync_utils_decode_hex (data->unwrap_kb);
+ if (!ephy_sync_crypto_derive_master_keys (bundle, data->resp_hmac_key,
+ data->resp_xor_key, unwrap_kb,
+ &ka, &kb)) {
ephy_sync_service_report_sign_in_error (self, _("Failed to retrieve the Sync Key"),
data->session_token, FALSE);
goto out;
@@ -1965,16 +1962,16 @@ ephy_sync_service_conclude_sign_in (EphySyncService *self,
self->user = g_strdup (data->email);
ephy_sync_service_set_secret (self, secrets[UID], data->uid);
ephy_sync_service_set_secret (self, secrets[SESSION_TOKEN], data->session_token);
- key_b_hex = ephy_sync_utils_encode_hex (key_b, 32);
- ephy_sync_service_set_secret (self, secrets[MASTER_KEY], key_b_hex);
+ kb_hex = ephy_sync_utils_encode_hex (kb, 32);
+ ephy_sync_service_set_secret (self, secrets[MASTER_KEY], kb_hex);
- ephy_sync_service_check_storage_version (self);
+ ephy_sync_service_verify_storage_version (self);
- g_free (key_b_hex);
- g_free (key_b);
- g_free (key_a);
+ g_free (kb_hex);
+ g_free (kb);
+ g_free (ka);
out:
- g_free (unwrap_key_b);
+ g_free (unwrap_kb);
sign_in_async_data_free (data);
}
@@ -2007,17 +2004,18 @@ get_account_keys_cb (SoupSession *session,
goto out_error;
}
/* Extract the master sync keys from the bundle and save tokens. */
- ephy_sync_service_conclude_sign_in (data->service, data, bundle);
+ ephy_sync_service_sign_in_finish (data->service, data, bundle);
goto out_no_error;
}
- /* If account is not verified, poll the Firefox Accounts Server until the
- * verification has completed. */
+ /* If account is not verified, poll the Firefox Accounts Server
+ * until the verification has completed.
+ */
if (json_object_get_int_member (json, "errno") == 104) {
LOG ("Account not verified, retrying...");
- ephy_sync_service_fxa_hawk_get_async (data->service, "account/keys",
- data->token_id_hex, data->req_hmac_key,
- 32, get_account_keys_cb, data);
+ ephy_sync_service_fxa_hawk_get (data->service, "account/keys",
+ data->token_id_hex, data->req_hmac_key, 32,
+ get_account_keys_cb, data);
goto out_no_error;
}
@@ -2037,12 +2035,12 @@ out_no_error:
}
void
-ephy_sync_service_do_sign_in (EphySyncService *self,
- const char *email,
- const char *uid,
- const char *session_token,
- const char *key_fetch_token,
- const char *unwrap_b_key)
+ephy_sync_service_sign_in (EphySyncService *self,
+ const char *email,
+ const char *uid,
+ const char *session_token,
+ const char *key_fetch_token,
+ const char *unwrap_kb)
{
SignInAsyncData *data;
guint8 *token_id;
@@ -2056,27 +2054,29 @@ ephy_sync_service_do_sign_in (EphySyncService *self,
g_return_if_fail (uid);
g_return_if_fail (session_token);
g_return_if_fail (key_fetch_token);
- g_return_if_fail (unwrap_b_key);
+ g_return_if_fail (unwrap_kb);
self->is_signing_in = TRUE;
/* Derive tokenID, reqHMACkey, respHMACkey and respXORkey from keyFetchToken.
- * tokenID and reqHMACkey are used to sign a HAWK GET requests to the /account/keys
+ * tokenID and reqHMACkey are used to sign HAWK GET requests to /account/keys
* endpoint. The server looks up the stored table entry with tokenID, checks
* the request HMAC for validity, then returns the pre-encrypted response.
- * See https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol#fetching-sync-keys */
- ephy_sync_crypto_process_key_fetch_token (key_fetch_token, &token_id, &req_hmac_key,
- &resp_hmac_key, &resp_xor_key, 32);
+ * See https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol#fetching-sync-keys
+ */
+ ephy_sync_crypto_derive_key_fetch_token (key_fetch_token,
+ &token_id, &req_hmac_key,
+ &resp_hmac_key, &resp_xor_key);
token_id_hex = ephy_sync_utils_encode_hex (token_id, 32);
/* Get the master sync key bundle from the /account/keys endpoint. */
data = sign_in_async_data_new (self, email, uid,
- session_token, unwrap_b_key,
+ session_token, unwrap_kb,
token_id_hex, req_hmac_key,
resp_hmac_key, resp_xor_key);
- ephy_sync_service_fxa_hawk_get_async (self, "account/keys", token_id_hex,
- req_hmac_key, 32,
- get_account_keys_cb, data);
+ ephy_sync_service_fxa_hawk_get (self, "account/keys",
+ token_id_hex, req_hmac_key, 32,
+ get_account_keys_cb, data);
g_free (token_id_hex);
g_free (token_id);
@@ -2294,7 +2294,7 @@ ephy_sync_service_unregister_device (EphySyncService *self)
}
void
-ephy_sync_service_do_sign_out (EphySyncService *self)
+ephy_sync_service_sign_out (EphySyncService *self)
{
g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
@@ -2315,21 +2315,21 @@ ephy_sync_service_do_sign_out (EphySyncService *self)
}
void
-ephy_sync_service_do_sync (EphySyncService *self)
+ephy_sync_service_sync (EphySyncService *self)
{
g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
g_return_if_fail (ephy_sync_utils_user_is_signed_in ());
- ephy_sync_service_sync (self);
+ ephy_sync_service_sync_internal (self);
}
void
-ephy_sync_service_start_periodical_sync (EphySyncService *self)
+ephy_sync_service_start_sync (EphySyncService *self)
{
g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
g_return_if_fail (ephy_sync_utils_user_is_signed_in ());
g_return_if_fail (self->sync_periodically);
- ephy_sync_service_sync (self);
+ ephy_sync_service_sync_internal (self);
ephy_sync_service_schedule_periodical_sync (self);
}
diff --git a/lib/sync/ephy-sync-service.h b/lib/sync/ephy-sync-service.h
index 3fdba7049..4668e13df 100644
--- a/lib/sync/ephy-sync-service.h
+++ b/lib/sync/ephy-sync-service.h
@@ -30,21 +30,21 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (EphySyncService, ephy_sync_service, EPHY, SYNC_SERVICE, GObject)
-EphySyncService *ephy_sync_service_new (gboolean sync_periodically);
-void ephy_sync_service_do_sign_in (EphySyncService *self,
- const char *email,
- const char *uid,
- const char *session_token,
- const char *key_fetch_token,
- const char *unwrap_b_key);
-void ephy_sync_service_do_sign_out (EphySyncService *self);
-void ephy_sync_service_do_sync (EphySyncService *self);
-void ephy_sync_service_start_periodical_sync (EphySyncService *self);
-void ephy_sync_service_register_device (EphySyncService *self,
- const char *device_name);
-void ephy_sync_service_register_manager (EphySyncService *self,
- EphySynchronizableManager *manager);
-void ephy_sync_service_unregister_manager (EphySyncService *self,
- EphySynchronizableManager *manager);
+EphySyncService *ephy_sync_service_new (gboolean sync_periodically);
+void ephy_sync_service_sign_in (EphySyncService *self,
+ const char *email,
+ const char *uid,
+ const char *session_token,
+ const char *key_fetch_token,
+ const char *unwrap_kb);
+void ephy_sync_service_sign_out (EphySyncService *self);
+void ephy_sync_service_sync (EphySyncService *self);
+void ephy_sync_service_start_sync (EphySyncService *self);
+void ephy_sync_service_register_device (EphySyncService *self,
+ const char *device_name);
+void ephy_sync_service_register_manager (EphySyncService *self,
+ EphySynchronizableManager *manager);
+void ephy_sync_service_unregister_manager (EphySyncService *self,
+ EphySynchronizableManager *manager);
G_END_DECLS
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index 9114088e5..4669198fd 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -181,7 +181,7 @@ prefs_dialog_finalize (GObject *object)
if (dialog->sync_service != NULL) {
if (ephy_sync_utils_user_is_signed_in () && !dialog->sync_was_signed_in)
- ephy_sync_service_start_periodical_sync (dialog->sync_service);
+ ephy_sync_service_start_sync (dialog->sync_service);
}
G_OBJECT_CLASS (prefs_dialog_parent_class)->finalize (object);
@@ -400,7 +400,7 @@ sync_fxa_server_message_cb (WebKitUserContentManager *manager,
const char *uid;
const char *session_token;
const char *key_fetch_token;
- const char *unwrap_b_key;
+ const char *unwrap_kb;
json_string = ephy_embed_utils_get_js_result_as_string (result);
if (!json_string) {
@@ -476,8 +476,8 @@ sync_fxa_server_message_cb (WebKitUserContentManager *manager,
uid = json_object_get_string_member (data, "uid");
session_token = json_object_get_string_member (data, "sessionToken");
key_fetch_token = json_object_get_string_member (data, "keyFetchToken");
- unwrap_b_key = json_object_get_string_member (data, "unwrapBKey");
- if (!email || !uid || !session_token || !key_fetch_token || !unwrap_b_key) {
+ unwrap_kb = json_object_get_string_member (data, "unwrapBKey");
+ if (!email || !uid || !session_token || !key_fetch_token || !unwrap_kb) {
g_warning ("JSON object has missing or invalid members");
goto out_error;
}
@@ -490,8 +490,8 @@ sync_fxa_server_message_cb (WebKitUserContentManager *manager,
if (!json_object_get_boolean_member (data, "verified"))
sync_sign_in_details_show (dialog, _("Please don’t leave this page until "
"you have completed the verification."));
- ephy_sync_service_do_sign_in (dialog->sync_service, email, uid,
- session_token, key_fetch_token, unwrap_b_key);
+ ephy_sync_service_sign_in (dialog->sync_service, email, uid,
+ session_token, key_fetch_token, unwrap_kb);
goto out_no_error;
out_error:
@@ -561,7 +561,7 @@ on_sync_sign_out_button_clicked (GtkWidget *button,
PrefsDialog *dialog)
{
- ephy_sync_service_do_sign_out (dialog->sync_service);
+ ephy_sync_service_sign_out (dialog->sync_service);
/* Show Firefox Accounts iframe. */
sync_setup_firefox_iframe (dialog);
@@ -582,7 +582,7 @@ on_sync_sync_now_button_clicked (GtkWidget *button,
PrefsDialog *dialog)
{
gtk_widget_set_sensitive (button, FALSE);
- ephy_sync_service_do_sync (dialog->sync_service);
+ ephy_sync_service_sync (dialog->sync_service);
}
static void