diff options
author | Gabriel Ivascu <ivascu.gabriel59@gmail.com> | 2017-06-12 18:05:49 +0300 |
---|---|---|
committer | Michael Catanzaro <mcatanzaro@igalia.com> | 2017-08-06 09:28:09 -0500 |
commit | c4c0acd128807c53bbf034be065bc22e98223d27 (patch) | |
tree | b5678b82f2a1d168a6fed510525de7d45a8768b4 | |
parent | ff16aaff81495e7b0eca03fb358236f68bd7bb96 (diff) | |
download | epiphany-c4c0acd128807c53bbf034be065bc22e98223d27.tar.gz |
sync: Rename and reorder some functions
-rw-r--r-- | lib/sync/README | 15 | ||||
-rw-r--r-- | lib/sync/debug/ephy-sync-debug.c | 33 | ||||
-rw-r--r-- | lib/sync/ephy-sync-crypto.c | 1307 | ||||
-rw-r--r-- | lib/sync/ephy-sync-crypto.h | 102 | ||||
-rw-r--r-- | lib/sync/ephy-sync-service.c | 450 | ||||
-rw-r--r-- | lib/sync/ephy-sync-service.h | 32 | ||||
-rw-r--r-- | src/prefs-dialog.c | 16 |
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 |